Browse Source

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

Lunny Xiao 11 years ago
parent
commit
a85f242030

+ 1 - 0
.gopmfile

@@ -19,6 +19,7 @@ github.com/lib/pq =
 github.com/nfnt/resize = 
 github.com/nfnt/resize = 
 github.com/qiniu/log = 
 github.com/qiniu/log = 
 github.com/robfig/cron = 
 github.com/robfig/cron = 
+github.com/juju2013/goldap = 
 
 
 [res]
 [res]
 include = templates|public|conf
 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
 ### 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.
 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.
 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)
 ![Demo](http://gowalker.org/public/gogs_demo.gif)
 
 
-##### Current version: 0.3.0 Alpha
+##### Current version: 0.3.1 Alpha
 
 
 ### NOTICES
 ### NOTICES
 
 
@@ -42,6 +42,11 @@ More importantly, Gogs only needs one binary to setup your own project hosting o
 - Supports MySQL, PostgreSQL and SQLite3.
 - Supports MySQL, PostgreSQL and SQLite3.
 - Social account login(GitHub, Google, QQ, Weibo)
 - 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
 ## Installation
 
 
 Make sure you install [Prerequirements](https://github.com/gogits/gogs/wiki/Prerequirements) first.
 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)
 ![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 数据库
 - 支持 MySQL、PostgreSQL 以及 SQLite3 数据库
 - 社交帐号登录(GitHub、Google、QQ、微博)
 - 社交帐号登录(GitHub、Google、QQ、微博)
 
 
+## 系统要求
+
+- 最低的系统硬件要求为一个廉价的树莓派
+- 如果用于团队项目,建议使用 4 核 CPU 及 1GB 内存
+
+
 ## 安装部署
 ## 安装部署
 
 
 在安装 Gogs 之前,您需要先安装 [基本环境](https://github.com/gogits/gogs/wiki/Prerequirements)。
 在安装 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
 PROTOCOL = http
 DOMAIN = localhost
 DOMAIN = localhost
 ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
 ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
+; Disable CDN even in "prod" mode
+OFFLINE_MODE = false
 HTTP_ADDR = 
 HTTP_ADDR = 
 HTTP_PORT = 3000
 HTTP_PORT = 3000
 ; Generate steps:
 ; Generate steps:

+ 2 - 2
doc/install_gogs_from_binary_on_ubuntu.md

@@ -18,8 +18,8 @@
 ### install the gogs
 ### install the gogs
 - mkdir gogs
 - mkdir gogs
 - cd 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
 - ./start.sh
 
 
 > The up-to-date binary could be found at
 > 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
 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 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 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
 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
 # Add PostgreSQL's repository. It contains the most recent stable release
 #     of PostgreSQL, ``9.3``.
 #     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
 # Update the Ubuntu and PostgreSQL repository indexes
 RUN apt-get update
 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.
 // Test that go1.2 tag above is included in builds. main.go refers to this definition.
 const go12tag = true
 const go12tag = true
 
 
-const APP_VER = "0.3.0.0422 Alpha"
+const APP_VER = "0.3.1.0427 Alpha"
 
 
 func init() {
 func init() {
 	base.AppVer = APP_VER
 	base.AppVer = APP_VER

+ 7 - 7
models/publickey.go

@@ -77,12 +77,12 @@ func init() {
 // PublicKey represents a SSH key of user.
 // PublicKey represents a SSH key of user.
 type PublicKey struct {
 type PublicKey struct {
 	Id          int64
 	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
 	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.
 // 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 {
 	if err = ioutil.WriteFile(tmpPath, []byte(key.Content), os.ModePerm); err != nil {
 		return err
 		return err
 	}
 	}
-	stdout, _, err := com.ExecCmd("ssh-keygen", "-l", "-f", tmpPath)
+	stdout, stderr, err := com.ExecCmd("ssh-keygen", "-l", "-f", tmpPath)
 	if err != nil {
 	if err != nil {
-		return err
+		return errors.New("ssh-keygen -l -f: " + stderr)
 	} else if len(stdout) < 2 {
 	} else if len(stdout) < 2 {
 		return errors.New("Not enough output for calculating fingerprint")
 		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")
 		repoPath := filepath.Join(base.RepoRootPath, m.RepoName+".git")
 		_, stderr, err := com.ExecCmdDir(repoPath, "git", "remote", "update")
 		_, stderr, err := com.ExecCmdDir(repoPath, "git", "remote", "update")
 		if err != nil {
 		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 {
 		} else if err = git.UnpackRefs(repoPath); err != nil {
 			return err
 			return err
 		}
 		}
@@ -177,9 +175,7 @@ func MirrorUpdate() {
 func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error {
 func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error {
 	_, stderr, err := com.ExecCmd("git", "clone", "--mirror", url, repoPath)
 	_, stderr, err := com.ExecCmd("git", "clone", "--mirror", url, repoPath)
 	if err != nil {
 	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{
 	if _, err = orm.InsertOne(&Mirror{
@@ -219,23 +215,17 @@ func MigrateRepository(user *User, name, desc string, private, mirror bool, url
 	// Clone from local repository.
 	// Clone from local repository.
 	_, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir)
 	_, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir)
 	if err != nil {
 	if err != nil {
-		return repo, err
-	} else if strings.Contains(stderr, "fatal:") {
 		return repo, errors.New("git clone: " + stderr)
 		return repo, errors.New("git clone: " + stderr)
 	}
 	}
 
 
 	// Pull data from source.
 	// Pull data from source.
 	_, stderr, err = com.ExecCmdDir(tmpDir, "git", "pull", url)
 	_, stderr, err = com.ExecCmdDir(tmpDir, "git", "pull", url)
 	if err != nil {
 	if err != nil {
-		return repo, err
-	} else if strings.Contains(stderr, "fatal:") {
 		return repo, errors.New("git pull: " + stderr)
 		return repo, errors.New("git pull: " + stderr)
 	}
 	}
 
 
 	// Push data to local repository.
 	// Push data to local repository.
 	if _, stderr, err = com.ExecCmdDir(tmpDir, "git", "push", "origin", "master"); err != nil {
 	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)
 		return repo, errors.New("git push: " + stderr)
 	}
 	}
 
 
@@ -403,10 +393,11 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep
 		return err
 		return err
 	}
 	}
 
 
+	rp := strings.NewReplacer("\\", "/", " ", "\\ ")
 	// hook/post-update
 	// hook/post-update
 	if err := createHookUpdate(filepath.Join(repoPath, "hooks", "update"),
 	if err := createHookUpdate(filepath.Join(repoPath, "hooks", "update"),
 		fmt.Sprintf("#!/usr/bin/env %s\n%s update $1 $2 $3\n", base.ScriptType,
 		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
 		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)
 	_, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir)
 	if err != nil {
 	if err != nil {
-		return err
-	} else if strings.Contains(stderr, "fatal:") {
 		return errors.New("git clone: " + stderr)
 		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
 package models
 
 
 import (
 import (
@@ -5,9 +9,11 @@ import (
 	"os/exec"
 	"os/exec"
 	"strings"
 	"strings"
 
 
+	qlog "github.com/qiniu/log"
+
 	"github.com/gogits/git"
 	"github.com/gogits/git"
+
 	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/base"
-	qlog "github.com/qiniu/log"
 )
 )
 
 
 func Update(refName, oldCommitId, newCommitId, userName, repoName string, userId int64) {
 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.
 // 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 {
 	if err != nil {
 		return nil, err
 		return nil, err
 	} else if !has {
 	} else if !has {
 		return nil, ErrUserNotExist
 		return nil, ErrUserNotExist
 	}
 	}
 
 
-	newUser := &User{Passwd: passwd, Salt: user.Salt}
+	newUser := &User{Passwd: passwd, Salt: u.Salt}
 	newUser.EncodePasswd()
 	newUser.EncodePasswd()
-	if user.Passwd != newUser.Passwd {
+	if u.Passwd != newUser.Passwd {
 		return nil, ErrUserNotExist
 		return nil, ErrUserNotExist
 	}
 	}
-	return &user, nil
+	return u, nil
 }
 }
 
 
 // Follow is connection request for receiving user notifycation.
 // 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 {
 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)"`
 	Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"`
 	Remember string `form:"remember"`
 	Remember string `form:"remember"`
 }
 }

+ 42 - 37
modules/base/conf.go

@@ -45,15 +45,15 @@ type Oauther struct {
 }
 }
 
 
 var (
 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
 	RepoRootPath string
 	ScriptType   string
 	ScriptType   string
@@ -93,6 +93,7 @@ var Service struct {
 	NotifyMail           bool
 	NotifyMail           bool
 	ActiveCodeLives      int
 	ActiveCodeLives      int
 	ResetPwdCodeLives    int
 	ResetPwdCodeLives    int
+	LdapAuth             bool
 }
 }
 
 
 func ExecDir() (string, error) {
 func ExecDir() (string, error) {
@@ -178,6 +179,36 @@ func newLogService() {
 	log.Info("Log Mode: %s(%s)", strings.Title(LogMode), levelName)
 	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() {
 func newCacheService() {
 	CacheAdapter = Cfg.MustValue("cache", "ADAPTER", "memory")
 	CacheAdapter = Cfg.MustValue("cache", "ADAPTER", "memory")
 	if EnableRedis {
 	if EnableRedis {
@@ -295,6 +326,7 @@ func NewConfigContext() {
 	AppLogo = Cfg.MustValue("", "APP_LOGO", "img/favicon.png")
 	AppLogo = Cfg.MustValue("", "APP_LOGO", "img/favicon.png")
 	AppUrl = Cfg.MustValue("server", "ROOT_URL")
 	AppUrl = Cfg.MustValue("server", "ROOT_URL")
 	Domain = Cfg.MustValue("server", "DOMAIN")
 	Domain = Cfg.MustValue("server", "DOMAIN")
+	OfflineMode = Cfg.MustBool("server", "OFFLINE_MODE", false)
 	SecretKey = Cfg.MustValue("security", "SECRET_KEY")
 	SecretKey = Cfg.MustValue("security", "SECRET_KEY")
 
 
 	InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false)
 	InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false)
@@ -312,34 +344,6 @@ func NewConfigContext() {
 	LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS")
 	LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS")
 	CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME")
 	CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME")
 	CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME")
 	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")
 	PictureService = Cfg.MustValue("picture", "SERVICE")
 
 
 	// Determine and create root git reposiroty path.
 	// Determine and create root git reposiroty path.
@@ -357,6 +361,7 @@ func NewConfigContext() {
 func NewBaseServices() {
 func NewBaseServices() {
 	newService()
 	newService()
 	newLogService()
 	newLogService()
+	newLdapService()
 	newCacheService()
 	newCacheService()
 	newSessionService()
 	newSessionService()
 	newMailService()
 	newMailService()

+ 5 - 5
modules/base/template.go

@@ -56,8 +56,8 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
 	"AppDomain": func() string {
 	"AppDomain": func() string {
 		return Domain
 		return Domain
 	},
 	},
-	"IsProdMode": func() bool {
-		return IsProdMode
+	"CdnMode": func() bool {
+		return ProdMode && !OfflineMode
 	},
 	},
 	"LoadTimes": func(startTime time.Time) string {
 	"LoadTimes": func(startTime time.Time) string {
 		return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
 		return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
@@ -124,11 +124,11 @@ func ActionIcon(opType int) string {
 const (
 const (
 	TPL_CREATE_REPO    = `<a href="/user/%s">%s</a> created repository <a href="/%s">%s</a>`
 	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    = `<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>
 	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>`
 <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_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 {
 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")
 			buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, AvatarLink(commit.AuthorEmail), repoLink, commit.Sha1, commit.Sha1[:7], commit.Message) + "\n")
 		}
 		}
 		if push.Len > 3 {
 		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,
 		return fmt.Sprintf(TPL_COMMIT_REPO, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink,
 			buf.String())
 			buf.String())

+ 5 - 2
modules/middleware/repo.go

@@ -26,11 +26,14 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler {
 		var displayBare bool
 		var displayBare bool
 
 
 		if len(args) >= 1 {
 		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 {
 		if len(args) >= 2 {
-			displayBare = args[1]
+			// displayBare = args[1]
+			displayBare = true
 		}
 		}
 
 
 		var (
 		var (

BIN
public/img/favicon.bak.png


BIN
public/img/favicon.png


+ 17 - 2
public/js/app.js

@@ -468,13 +468,28 @@ function initRepository() {
 function initInstall() {
 function initInstall() {
     // database type change
     // database type change
     (function () {
     (function () {
+        var mysql_default    = '127.0.0.1:3306'
+        var postgres_default = '127.0.0.1:5432'
+
         $('#install-database').on("change", function () {
         $('#install-database').on("change", function () {
             var val = $(this).val();
             var val = $(this).val();
-            if (val != "sqlite") {
+            if (val != "SQLite3") {
                 $('.server-sql').show();
                 $('.server-sql').show();
                 $('.sqlite-setting').addClass("hide");
                 $('.sqlite-setting').addClass("hide");
-                if (val == "pgsql") {
+                if (val == "PostgreSQL") {
                     $('.pgsql-setting').removeClass("hide");
                     $('.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 {
                 } else {
                     $('.pgsql-setting').addClass("hide");
                     $('.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["AppUrl"] = base.AppUrl
 	ctx.Data["Domain"] = base.Domain
 	ctx.Data["Domain"] = base.Domain
+	ctx.Data["OfflineMode"] = base.OfflineMode
 	ctx.Data["RunUser"] = base.RunUser
 	ctx.Data["RunUser"] = base.RunUser
 	ctx.Data["RunMode"] = strings.Title(martini.Env)
 	ctx.Data["RunMode"] = strings.Title(martini.Env)
 	ctx.Data["RepoRootPath"] = base.RepoRootPath
 	ctx.Data["RepoRootPath"] = base.RepoRootPath
+	ctx.Data["ScriptType"] = base.ScriptType
 
 
 	ctx.Data["Service"] = base.Service
 	ctx.Data["Service"] = base.Service
 
 

+ 16 - 2
routers/install.go

@@ -30,7 +30,7 @@ func checkRunMode() {
 	switch base.Cfg.MustValue("", "RUN_MODE") {
 	switch base.Cfg.MustValue("", "RUN_MODE") {
 	case "prod":
 	case "prod":
 		martini.Env = martini.Prod
 		martini.Env = martini.Prod
-		base.IsProdMode = true
+		base.ProdMode = true
 	case "test":
 	case "test":
 		martini.Env = martini.Test
 		martini.Env = martini.Test
 	}
 	}
@@ -65,6 +65,10 @@ func GlobalInit() {
 	checkRunMode()
 	checkRunMode()
 }
 }
 
 
+func renderDbOption(ctx *middleware.Context) {
+	ctx.Data["DbOptions"] = []string{"MySQL", "PostgreSQL", "SQLite3"}
+}
+
 func Install(ctx *middleware.Context, form auth.InstallForm) {
 func Install(ctx *middleware.Context, form auth.InstallForm) {
 	if base.InstallLock {
 	if base.InstallLock {
 		ctx.Handle(404, "install.Install", errors.New("Installation is prohibited"))
 		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
 		form.AppUrl = base.AppUrl
 	}
 	}
 
 
+	renderDbOption(ctx)
+	curDbValue := ""
+	if models.EnableSQLite3 {
+		curDbValue = "SQLite3" // Default when enabled.
+	}
+	ctx.Data["CurDbValue"] = curDbValue
+
 	auth.AssignForm(form, ctx.Data)
 	auth.AssignForm(form, ctx.Data)
 	ctx.HTML(200, "install")
 	ctx.HTML(200, "install")
 }
 }
@@ -117,6 +128,9 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
 	ctx.Data["Title"] = "Install"
 	ctx.Data["Title"] = "Install"
 	ctx.Data["PageIsInstall"] = true
 	ctx.Data["PageIsInstall"] = true
 
 
+	renderDbOption(ctx)
+	ctx.Data["CurDbValue"] = form.Database
+
 	if ctx.HasError() {
 	if ctx.HasError() {
 		ctx.HTML(200, "install")
 		ctx.HTML(200, "install")
 		return
 		return
@@ -129,7 +143,7 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
 
 
 	// Pass basic check, now test configuration.
 	// Pass basic check, now test configuration.
 	// Test database setting.
 	// 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.Type = dbTypes[form.Database]
 	models.DbCfg.Host = form.Host
 	models.DbCfg.Host = form.Host
 	models.DbCfg.User = form.User
 	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
 		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["IsImageFile"] = isImageFile
-	ctx.Data["Title"] = commit.Message() + " · " + base.ShortSha(commitId)
+	ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitId)
 	ctx.Data["Commit"] = commit
 	ctx.Data["Commit"] = commit
 	ctx.Data["Diff"] = diff
 	ctx.Data["Diff"] = diff
+	ctx.Data["Parents"] = parents
 	ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
 	ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
 	ctx.Data["IsRepoToolbarCommits"] = true
 	ctx.Data["IsRepoToolbarCommits"] = true
 	ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId)
 	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
 			return
 		}
 		}
 
 
-		k := &models.PublicKey{OwnerId: ctx.User.Id,
+		k := &models.PublicKey{
+			OwnerId: ctx.User.Id,
 			Name:    form.KeyName,
 			Name:    form.KeyName,
 			Content: form.KeyContent,
 			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 user *models.User
 	var err error
 	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)
 		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
 	// 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)
 		user, err = models.LoginUserPlain(form.UserName, form.Password)
 	}
 	}
 	if err != nil {
 	if err != nil {
@@ -142,27 +144,6 @@ func SignInPost(ctx *middleware.Context, form auth.LogInForm) {
 	ctx.Redirect("/")
 	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) {
 func SignOut(ctx *middleware.Context) {
 	ctx.Session.Delete("userId")
 	ctx.Session.Delete("userId")
 	ctx.Session.Delete("userName")
 	ctx.Session.Delete("userName")

+ 4 - 0
templates/admin/config.tmpl

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

+ 4 - 1
templates/base/footer.tmpl

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

+ 1 - 1
templates/base/head.tmpl

@@ -12,7 +12,7 @@
 		{{if .Repository.IsGoget}}<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">{{end}}
 		{{if .Repository.IsGoget}}<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">{{end}}
 
 
 		 <!-- Stylesheets -->
 		 <!-- Stylesheets -->
-		{{if IsProdMode}}
+		{{if CdnMode}}
 		<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
 		<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">
 		<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">
         <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 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 .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">
             {{if .HasAccess}}<!-- <form class="nav-item pull-left{{if .PageIsNewRepo}} active{{end}}" id="nav-search-form">
                 <div class="input-group">
                 <div class="input-group">
                     <div class="input-group-btn">
                     <div class="input-group-btn">
@@ -33,8 +33,8 @@
                     </ul>
                     </ul>
                 </div>
                 </div>
             </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>
         </nav>
     </div>
     </div>
 </div>
 </div>

+ 8 - 7
templates/install.tmpl

@@ -9,18 +9,19 @@
             <label class="col-md-3 control-label">Database Type: </label>
             <label class="col-md-3 control-label">Database Type: </label>
             <div class="col-md-8">
             <div class="col-md-8">
                 <select name="database" id="install-database" class="form-control">
                 <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>
                 </select>
             </div>
             </div>
         </div>
         </div>
 
 
-        <div class="server-sql">
+        <div class="server-sql {{if eq .CurDbValue "SQLite3"}}hide{{end}}">
             <div class="form-group">
             <div class="form-group">
                 <label class="col-md-3 control-label">Host: </label>
                 <label class="col-md-3 control-label">Host: </label>
                 <div class="col-md-8">
                 <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>
             </div>
             </div>
 
 
@@ -49,7 +50,7 @@
                 </div>
                 </div>
             </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>
                 <label class="col-md-3 control-label">SSL Mode: </label>
                 <div class="col-md-8">
                 <div class="col-md-8">
                     <select name="ssl_mode" class="form-control">
                     <select name="ssl_mode" class="form-control">
@@ -61,7 +62,7 @@
             </div>
             </div>
         </div>
         </div>
 
 
-        <div class="sqlite-setting hide">
+        <div class="sqlite-setting {{if not (eq .CurDbValue "SQLite3")}}hide{{end}}">
             <div class="form-group">
             <div class="form-group">
                 <label class="col-md-3 control-label">Path: </label>
                 <label class="col-md-3 control-label">Path: </label>
 
 

+ 6 - 30
templates/release/list.tmpl

@@ -15,8 +15,8 @@
                 {{if .PublisherId}}
                 {{if .PublisherId}}
                 <div class="col-md-2 text-right">
                 <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}}
                     {{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>
                 <div class="col-md-10">
                 <div class="col-md-10">
                     <h4 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}">{{.Title}}</a></h4>
                     <h4 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}">{{.Title}}</a></h4>
@@ -30,19 +30,19 @@
                         {{str2html .Note}}
                         {{str2html .Note}}
                     </div>
                     </div>
                     <p class="download">
                     <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> -->
                         <!-- <a class="btn btn-default" href="{release_download_link}"><i class="fa fa-download"></i>Source Code (TAR.GZ)</a> -->
                     </p>
                     </p>
                     <span class="dot">&nbsp;</span>
                     <span class="dot">&nbsp;</span>
                 </div>
                 </div>
                 {{else}}
                 {{else}}
                 <div class="col-md-2 text-right">
                 <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>
                 <div class="col-md-10">
                 <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">
                     <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> -->
                         <!-- <a class="download-link" href="{release_download_link}"><i class="fa fa-download"></i>tar.gz</a> -->
                     </p>
                     </p>
                     <span class="dot">&nbsp;</span>
                     <span class="dot">&nbsp;</span>
@@ -50,30 +50,6 @@
                 {{end}}
                 {{end}}
             </li>
             </li>
             {{end}}
             {{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>
         </ul>
     </div>
     </div>
 </div>
 </div>

+ 3 - 3
templates/repo/commits.tmpl

@@ -33,7 +33,7 @@
                 <tr>
                 <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="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="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>
                     <td class="date">{{TimeSince .Author.When}}</td>
                 </tr>
                 </tr>
                 {{end}}
                 {{end}}
@@ -41,8 +41,8 @@
             </table>
             </table>
         </div>
         </div>
         {{if not .IsSearchPage}}<ul class="pagination" id="commits-pager">
         {{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}}
         </ul>{{end}}
     </div>
     </div>
 </div>
 </div>

+ 6 - 1
templates/repo/diff.tmpl

@@ -10,7 +10,12 @@
             </div>
             </div>
             <div class="panel-body">
             <div class="panel-body">
                 <span class="pull-right">
                 <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>
                 </span>
                 <p class="author">
                 <p class="author">
                     <img class="avatar" src="{{AvatarLink .Commit.Author.Email}}" alt=""/>
                     <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>
                                 <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>
                             </span>
                         </div>
                         </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/>
                         <hr/>
                         <div class="clone-zip text-center">
                         <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>
                     </div>
                 </div>
                 </div>

+ 24 - 23
templates/repo/single_file.tmpl

@@ -14,37 +14,38 @@
         {{if not .ReadmeInSingle}}
         {{if not .ReadmeInSingle}}
         <div class="btn-group pull-right">
         <div class="btn-group pull-right">
             <a class="btn btn-default hidden" href="#">Edit</a>
             <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="#">Blame</a>
             <a class="btn btn-default hidden" href="#">History</a>
             <a class="btn btn-default hidden" href="#">History</a>
             <a class="btn btn-danger hidden" href="#">Delete</a>
             <a class="btn btn-danger hidden" href="#">Delete</a>
         </div>
         </div>
         {{end}}
         {{end}}
     </div>
     </div>
+    
     {{if not .FileIsText}}
     {{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}}
         {{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}}
         {{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}}
     {{end}}
 </div>
 </div>

+ 2 - 2
templates/repo/single_list.tmpl

@@ -1,6 +1,6 @@
 <div class="panel panel-default info-box">
 <div class="panel panel-default info-box">
     <div class="panel-heading info-head">
     <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>
     <div class="panel-body info-content">
     <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>
         <a href="/user/{{.LastCommit.Author.Name}}">{{.LastCommit.Author.Name}}</a> <span class="text-muted">{{TimeSince .LastCommit.Author.When}}</span>
@@ -36,7 +36,7 @@
                         </span>
                         </span>
                     </td>
                     </td>
                     <td class="text">
                     <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>
                     <td class="date">
                     <td class="date">
                         <span class="wrap">{{TimeSince $commit.Committer.When}}</span>
                         <span class="wrap">{{TimeSince $commit.Committer.When}}</span>

+ 3 - 3
templates/user/profile.tmpl

@@ -11,13 +11,13 @@
         <div class="profile-info">
         <div class="profile-info">
             <ul class="list-group">
             <ul class="list-group">
                 {{if .Owner.Location}}
                 {{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}}
                 {{end}}
                 {{if .Owner.Email}}
                 {{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}}
                 {{end}}
                 {{if .Owner.Website}}
                 {{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}}
                 {{end}}
                 <li class="list-group-item"><i class="fa fa-clock-o"></i>Joined on {{DateFormat .Owner.Created "M d, Y"}}</li>
                 <li class="list-group-item"><i class="fa fa-clock-o"></i>Joined on {{DateFormat .Owner.Created "M d, Y"}}</li>
                 <!-- <hr> -->
                 <!-- <hr> -->

+ 1 - 1
templates/user/signin.tmpl

@@ -10,7 +10,7 @@
         {{end}}
         {{end}}
         {{template "base/alert" .}}
         {{template "base/alert" .}}
         <div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}">
         <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">
             <div class="col-md-6">
                 <input name="username" class="form-control" placeholder="Type your username" value="{{.username}}" required="required">
                 <input name="username" class="form-control" placeholder="Type your username" value="{{.username}}" required="required">
             </div>
             </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)
-	}
-}