]> source.dussan.org Git - gitea.git/commitdiff
#1597 support pull requests in same repository
authorUnknwon <u@gogs.io>
Fri, 4 Mar 2016 20:43:01 +0000 (15:43 -0500)
committerUnknwon <u@gogs.io>
Fri, 4 Mar 2016 20:43:01 +0000 (15:43 -0500)
13 files changed:
README.md
cmd/web.go
gogs.go
models/pull.go
models/repo.go
models/user.go
modules/log/database.go [deleted file]
modules/middleware/repo.go
routers/repo/pull.go
templates/.VERSION
templates/repo/home.tmpl
templates/repo/issue/list.tmpl
templates/repo/pulls/compare.tmpl

index 02dff0efc2238f93f248da64779631f442fba21b..cd4a816131a91d0fc064e7c98b4b7f472b035b4e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
 
 ![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true)
 
-##### Current version: 0.8.56
+##### Current version: 0.8.57
 
 | Web | UI  | Preview  |
 |:-------------:|:-------:|:-------:|
index 2e4989039cea9a3ea4cbd698c9cea1ce95a852c7..7158f09a34c14af10779ee0a8016907ba401f6ae 100644 (file)
@@ -79,7 +79,7 @@ func checkVersion() {
 
        // Check dependency version.
        checkers := []VerChecker{
-               {"github.com/go-xorm/xorm", func() string { return xorm.Version }, "0.4.4.1029"},
+               {"github.com/go-xorm/xorm", func() string { return xorm.Version }, "0.5.2.0304"},
                {"github.com/go-macaron/binding", binding.Version, "0.2.1"},
                {"github.com/go-macaron/cache", cache.Version, "0.1.2"},
                {"github.com/go-macaron/csrf", csrf.Version, "0.0.3"},
@@ -88,7 +88,7 @@ func checkVersion() {
                {"github.com/go-macaron/toolbox", toolbox.Version, "0.1.0"},
                {"gopkg.in/ini.v1", ini.Version, "1.8.4"},
                {"gopkg.in/macaron.v1", macaron.Version, "0.8.0"},
-               {"github.com/gogits/git-module", git.Version, "0.2.8"},
+               {"github.com/gogits/git-module", git.Version, "0.2.9"},
                {"github.com/gogits/go-gogs-client", gogs.Version, "0.7.3"},
        }
        for _, c := range checkers {
diff --git a/gogs.go b/gogs.go
index 4ca4382f19a1abc1b253d50c03e6bf34120a90b5..6cad5fe3c46f95254a98ce74bc25800130ec46fe 100644 (file)
--- a/gogs.go
+++ b/gogs.go
@@ -17,7 +17,7 @@ import (
        "github.com/gogits/gogs/modules/setting"
 )
 
-const APP_VER = "0.8.56.0304"
+const APP_VER = "0.8.57.0304"
 
 func init() {
        runtime.GOMAXPROCS(runtime.NumCPU())
index 276dc1bcfd768aa749cf882cec22b6c1199d7b6b..77484b95628b97cb5b613976754786356d4d447b 100644 (file)
@@ -487,7 +487,7 @@ func (pr *PullRequest) UpdatePatch() (err error) {
 // FIXME: could fail after user force push head repo, should we always force push here?
 // FIXME: Only push branches that are actually updates?
 func (pr *PullRequest) PushToBaseRepo() (err error) {
-       log.Trace("PushToBaseRepo[%[1]d]: pushing commits to base repo 'refs/pull/%[1]d/head'", pr.ID)
+       log.Trace("PushToBaseRepo[%d]: pushing commits to base repo 'refs/pull/%d/head'", pr.BaseRepoID, pr.Index)
 
        headRepoPath := pr.HeadRepo.RepoPath()
        headGitRepo, err := git.OpenRepository(headRepoPath)
index 17c0082cbd5518bf888cff583f88b369e7af586f..3f631b698434ee6e73513882fdbe4509b8ea351c 100644 (file)
@@ -184,6 +184,11 @@ type Repository struct {
 
 func (repo *Repository) AfterSet(colName string, _ xorm.Cell) {
        switch colName {
+       case "default_branch":
+               // FIXME: use models migration to solve all at once.
+               if len(repo.DefaultBranch) == 0 {
+                       repo.DefaultBranch = "master"
+               }
        case "num_closed_issues":
                repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
        case "num_closed_pulls":
index 3264c0634b87819cc9fad4da6b67d86ad933b7e3..6e7c27293de51ec1cbacb4477f4803e523b64f3b 100644 (file)
@@ -348,16 +348,10 @@ func (u *User) UploadAvatar(data []byte) error {
 
 // IsAdminOfRepo returns true if user has admin or higher access of repository.
 func (u *User) IsAdminOfRepo(repo *Repository) bool {
-       if err := repo.GetOwner(); err != nil {
-               log.Error(3, "GetOwner: %v", err)
-               return false
-       }
-
-       if repo.Owner.IsOrganization() {
+       if repo.MustOwner().IsOrganization() {
                has, err := HasAccess(u, repo, ACCESS_MODE_ADMIN)
                if err != nil {
                        log.Error(3, "HasAccess: %v", err)
-                       return false
                }
                return has
        }
@@ -365,6 +359,15 @@ func (u *User) IsAdminOfRepo(repo *Repository) bool {
        return repo.IsOwnedBy(u.Id)
 }
 
+// CanWriteTo returns true if user has write access to given repository.
+func (u *User) CanWriteTo(repo *Repository) bool {
+       has, err := HasAccess(u, repo, ACCESS_MODE_WRITE)
+       if err != nil {
+               log.Error(3, "HasAccess: %v", err)
+       }
+       return has
+}
+
 // IsOrganization returns true if user is actually a organization.
 func (u *User) IsOrganization() bool {
        return u.Type == ORGANIZATION
diff --git a/modules/log/database.go b/modules/log/database.go
deleted file mode 100644 (file)
index 5857cb6..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-// 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 log
-
-import (
-       "encoding/json"
-
-       "github.com/go-xorm/xorm"
-)
-
-type Log struct {
-       Id    int64
-       Level int
-       Msg   string `xorm:"TEXT"`
-}
-
-// DatabaseWriter implements LoggerInterface and is used to log into database.
-type DatabaseWriter struct {
-       Driver string `json:"driver"`
-       Conn   string `json:"conn"`
-       Level  int    `json:"level"`
-       x      *xorm.Engine
-}
-
-func NewDatabase() LoggerInterface {
-       return &DatabaseWriter{Level: TRACE}
-}
-
-// init database writer with json config.
-// config like:
-//     {
-//             "driver": "mysql"
-//             "conn":"root:root@tcp(127.0.0.1:3306)/gogs?charset=utf8",
-//             "level": 0
-//     }
-// connection string is based on xorm.
-func (d *DatabaseWriter) Init(jsonconfig string) (err error) {
-       if err = json.Unmarshal([]byte(jsonconfig), d); err != nil {
-               return err
-       }
-       d.x, err = xorm.NewEngine(d.Driver, d.Conn)
-       if err != nil {
-               return err
-       }
-       return d.x.Sync(new(Log))
-}
-
-// write message in database writer.
-func (d *DatabaseWriter) WriteMsg(msg string, skip, level int) error {
-       if level < d.Level {
-               return nil
-       }
-
-       _, err := d.x.Insert(&Log{Level: level, Msg: msg})
-       return err
-}
-
-func (_ *DatabaseWriter) Flush() {
-}
-
-func (_ *DatabaseWriter) Destroy() {
-}
-
-func init() {
-       Register("database", NewDatabase)
-}
index 002982656d4ae5d3bf048fdd983b821e3ba62c2f..7c99d2d0c1940d53e7d82f8e3d77a40b4ec4bc8e 100644 (file)
@@ -32,25 +32,6 @@ func RetrieveBaseRepo(ctx *Context, repo *models.Repository) {
                ctx.Handle(500, "BaseRepo.GetOwner", err)
                return
        }
-
-       bsaeRepo := repo.BaseRepo
-       baseGitRepo, err := git.OpenRepository(models.RepoPath(bsaeRepo.Owner.Name, bsaeRepo.Name))
-       if err != nil {
-               ctx.Handle(500, "OpenRepository", err)
-               return
-       }
-       if len(bsaeRepo.DefaultBranch) > 0 && baseGitRepo.IsBranchExist(bsaeRepo.DefaultBranch) {
-               ctx.Data["BaseDefaultBranch"] = bsaeRepo.DefaultBranch
-       } else {
-               baseBranches, err := baseGitRepo.GetBranches()
-               if err != nil {
-                       ctx.Handle(500, "GetBranches", err)
-                       return
-               }
-               if len(baseBranches) > 0 {
-                       ctx.Data["BaseDefaultBranch"] = baseBranches[0]
-               }
-       }
 }
 
 func RepoAssignment(args ...bool) macaron.Handler {
@@ -154,6 +135,13 @@ func RepoAssignment(args ...bool) macaron.Handler {
                ctx.Data["Tags"] = tags
                ctx.Repo.Repository.NumTags = len(tags)
 
+               ctx.Data["Title"] = owner.Name + "/" + repo.Name
+               ctx.Data["Repository"] = repo
+               ctx.Data["Owner"] = ctx.Repo.Repository.Owner
+               ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
+               ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
+               ctx.Data["IsRepositoryPusher"] = ctx.Repo.IsPusher()
+
                if repo.IsFork {
                        RetrieveBaseRepo(ctx, repo)
                        if ctx.Written() {
@@ -161,13 +149,24 @@ func RepoAssignment(args ...bool) macaron.Handler {
                        }
                }
 
-               ctx.Data["Title"] = owner.Name + "/" + repo.Name
-               ctx.Data["Repository"] = repo
-               ctx.Data["Owner"] = ctx.Repo.Repository.Owner
-               ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
-               ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
-               ctx.Data["IsRepositoryPusher"] = ctx.Repo.IsPusher()
-               ctx.Data["CanPullRequest"] = ctx.Repo.IsAdmin() && repo.BaseRepo != nil && repo.BaseRepo.AllowsPulls()
+               // People who have push access and propose a new pull request.
+               if ctx.Repo.IsPusher() {
+                       // Pull request is allowed if this is a fork repository
+                       // and base repository accepts pull requests.
+                       if repo.BaseRepo != nil {
+                               if repo.BaseRepo.AllowsPulls() {
+                                       ctx.Data["CanPullRequest"] = true
+                                       ctx.Data["BaseRepo"] = repo.BaseRepo
+                               }
+                       } else {
+                               // Or, this is repository accepts pull requests between branches.
+                               if repo.AllowsPulls() {
+                                       ctx.Data["CanPullRequest"] = true
+                                       ctx.Data["BaseRepo"] = repo
+                                       ctx.Data["IsBetweenBranches"] = true
+                               }
+                       }
+               }
 
                ctx.Data["DisableSSH"] = setting.SSH.Disabled
                ctx.Data["CloneLink"] = repo.CloneLink()
index 58acb1758d95ff9f07ce351c3aead18ed0004829..e42ac61250f7f59f7e54e1c47723b24510ab5ff1 100644 (file)
@@ -414,9 +414,13 @@ func MergePullRequest(ctx *middleware.Context) {
 }
 
 func ParseCompareInfo(ctx *middleware.Context) (*models.User, *models.Repository, *git.Repository, *git.PullRequestInfo, string, string) {
-       // Get compare branch information.
+       // Get compared branches information
+       // format: <base branch>...[<head repo>:]<head branch>
+       // base<-head: master...head:feature
+       // same repo: master...feature
        infos := strings.Split(ctx.Params("*"), "...")
        if len(infos) != 2 {
+               log.Trace("Not enough compared branches information: %s", infos)
                ctx.Handle(404, "CompareAndPullRequest", nil)
                return nil, nil, nil, nil, "", ""
        }
@@ -424,25 +428,39 @@ func ParseCompareInfo(ctx *middleware.Context) (*models.User, *models.Repository
        baseBranch := infos[0]
        ctx.Data["BaseBranch"] = baseBranch
 
+       var (
+               headUser   *models.User
+               headBranch string
+               isSameRepo bool
+               err        error
+       )
+
+       // If there is no head repository, it means pull request between same repository.
        headInfos := strings.Split(infos[1], ":")
-       if len(headInfos) != 2 {
-               ctx.Handle(404, "CompareAndPullRequest", nil)
-               return nil, nil, nil, nil, "", ""
-       }
-       headUsername := headInfos[0]
-       headBranch := headInfos[1]
-       ctx.Data["HeadBranch"] = headBranch
+       if len(headInfos) == 1 {
+               isSameRepo = true
+               headUser = ctx.Repo.Owner
+               headBranch = headInfos[0]
 
-       headUser, err := models.GetUserByName(headUsername)
-       if err != nil {
-               if models.IsErrUserNotExist(err) {
-                       ctx.Handle(404, "GetUserByName", nil)
-               } else {
-                       ctx.Handle(500, "GetUserByName", err)
+       } else if len(headInfos) == 2 {
+               headUser, err = models.GetUserByName(headInfos[0])
+               if err != nil {
+                       if models.IsErrUserNotExist(err) {
+                               ctx.Handle(404, "GetUserByName", nil)
+                       } else {
+                               ctx.Handle(500, "GetUserByName", err)
+                       }
+                       return nil, nil, nil, nil, "", ""
                }
+               headBranch = headInfos[1]
+
+       } else {
+               ctx.Handle(404, "CompareAndPullRequest", nil)
                return nil, nil, nil, nil, "", ""
        }
        ctx.Data["HeadUser"] = headUser
+       ctx.Data["HeadBranch"] = headBranch
+       ctx.Data["IsBetweenBranches"] = isSameRepo
 
        repo := ctx.Repo.Repository
 
@@ -452,17 +470,23 @@ func ParseCompareInfo(ctx *middleware.Context) (*models.User, *models.Repository
                return nil, nil, nil, nil, "", ""
        }
 
-       // Check if current user has fork of repository.
+       // Check if current user has fork of repository or in the same repository.
        headRepo, has := models.HasForkedRepo(headUser.Id, repo.ID)
-       if !has || (!ctx.User.IsAdminOfRepo(headRepo) && !ctx.User.IsAdmin) {
+       if (!has && !isSameRepo) || (!ctx.User.CanWriteTo(headRepo) && !ctx.User.IsAdmin) {
                ctx.Handle(404, "HasForkedRepo", nil)
                return nil, nil, nil, nil, "", ""
        }
 
-       headGitRepo, err := git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name))
-       if err != nil {
-               ctx.Handle(500, "OpenRepository", err)
-               return nil, nil, nil, nil, "", ""
+       var headGitRepo *git.Repository
+       if isSameRepo {
+               headRepo = ctx.Repo.Repository
+               headGitRepo = ctx.Repo.GitRepo
+       } else {
+               headGitRepo, err = git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name))
+               if err != nil {
+                       ctx.Handle(500, "OpenRepository", err)
+                       return nil, nil, nil, nil, "", ""
+               }
        }
 
        // Check if head branch is valid.
@@ -648,8 +672,7 @@ func CompareAndPullRequestPost(ctx *middleware.Context, form auth.CreateIssueFor
        if err := models.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch); err != nil {
                ctx.Handle(500, "NewPullRequest", err)
                return
-       }
-       if err := pullRequest.PushToBaseRepo(); err != nil {
+       } else if err := pullRequest.PushToBaseRepo(); err != nil {
                ctx.Handle(500, "PushToBaseRepo", err)
                return
        }
index b147b846a120b7953f7bfe431db338c81452d8f8..76f54f43fe27777aafa35f3dd70312291e38349f 100644 (file)
@@ -1 +1 @@
-0.8.56.0304
\ No newline at end of file
+0.8.57.0304
\ No newline at end of file
index 47d53bf13c6198377cb31ac0a3565ab6195b6324..36752a6eab97ebf2d78e295debccb46f2fe3f6ec 100644 (file)
@@ -9,8 +9,7 @@
                <div class="ui secondary menu">
                        {{if .CanPullRequest}}
                                <div class="fitted item">
-                                       {{ $baseRepo := .Repository.BaseRepo}}
-                                       <a href="{{AppSubUrl}}/{{$baseRepo.Owner.Name}}/{{$baseRepo.Name}}/compare/{{$.BaseDefaultBranch}}...{{$.Owner.Name}}:{{$.BranchName}}">
+                                       <a href="{{.BaseRepo.RepoLink}}/compare/{{.BaseRepo.DefaultBranch}}...{{if not .IsBetweenBranches}}{{$.Owner.Name}}:{{end}}{{$.BranchName}}">
                                                <button class="ui green small button"><i class="octicon octicon-git-compare"></i></button>
                                        </a>
                                </div>
index 790a6572e47583c2c2375dc1dede60c2324e4d31..b4e79ee9c6a60c682d1764f609b88ab2ea5bdbc8 100644 (file)
@@ -8,7 +8,7 @@
                                {{if .PageIsIssueList}}
                                        <a class="ui green button" href="{{.RepoLink}}/issues/new">{{.i18n.Tr "repo.issues.new"}}</a>
                                {{else}}
-                                       <a class="ui green button {{if not .HasForkedRepo}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName}}...{{.SignedUserName}}:{{.BranchName}}">{{.i18n.Tr "repo.pulls.new"}}</a>
+                                       <a class="ui green button {{if not (or .CanPullRequest .HasForkedRepo)}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.Repository.DefaultBranch}}...{{if not (eq .Owner.Name .SignedUserName)}}{{.SignedUserName}}:{{end}}{{.BranchName}}">{{.i18n.Tr "repo.pulls.new"}}</a>
                                {{end}}
                        </div>
                </div>
index 110dfa46b381452fe151b2975e3e884520b95f5a..30a2fd5b695cd6e8d9804440b4ef044cdcf54b30 100644 (file)
@@ -21,7 +21,7 @@
                                                </div>
                                                <div class="scrolling menu">
                                                        {{range .Branches}}
-                                                               <div class="item {{if eq $.BaseBranch .}}selected{{end}}" data-url="{{$.RepoLink}}/compare/{{.}}...{{$.HeadUser.Name}}:{{$.HeadBranch}}">{{.}}</div>
+                                                               <div class="item {{if eq $.BaseBranch .}}selected{{end}}" data-url="{{$.RepoLink}}/compare/{{.}}...{{if not $.IsBetweenBranches}}{{$.HeadUser.Name}}:{{end}}{{$.HeadBranch}}">{{.}}</div>
                                                        {{end}}
                                                </div>
                                        </div>
@@ -39,7 +39,7 @@
                                                </div>
                                                <div class="scrolling menu">
                                                        {{range .HeadBranches}}
-                                                               <div class="{{if eq $.HeadBranch .}}selected{{end}} item" data-url="{{$.RepoLink}}/compare/{{$.BaseBranch}}...{{$.HeadUser.Name}}:{{.}}">{{.}}</div>
+                                                               <div class="{{if eq $.HeadBranch .}}selected{{end}} item" data-url="{{$.RepoLink}}/compare/{{$.BaseBranch}}...{{if not $.IsBetweenBranches}}{{$.HeadUser.Name}}:{{end}}{{.}}">{{.}}</div>
                                                        {{end}}
                                                </div>
                                        </div>