mirror of
https://github.com/gogs/gogs.git
synced 2025-04-28 13:50:35 +00:00
We used to handle SSH and HTTP push separately which produces duplicated code, but now with post-receive hook, the process is unified to one single place and much cleaner. Thus, UpdateTask struct is removed. Narrow down the range of Git HTTP routes to reduce condufsing HTTP Basic Authentication window popup on browser. By detecting <old-commit, new-commit, ref-name> inside post-receive hook, Git HTTP doesn't need to read the whole content body anymore, which completely solve the RAM problem reported in #636.
140 lines
3.6 KiB
Go
140 lines
3.6 KiB
Go
// 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 (
|
|
"container/list"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
log "gopkg.in/clog.v1"
|
|
|
|
git "github.com/gogits/git-module"
|
|
)
|
|
|
|
// CommitToPushCommit transforms a git.Commit to PushCommit type.
|
|
func CommitToPushCommit(commit *git.Commit) *PushCommit {
|
|
return &PushCommit{
|
|
Sha1: commit.ID.String(),
|
|
Message: commit.Message(),
|
|
AuthorEmail: commit.Author.Email,
|
|
AuthorName: commit.Author.Name,
|
|
CommitterEmail: commit.Committer.Email,
|
|
CommitterName: commit.Committer.Name,
|
|
Timestamp: commit.Committer.When,
|
|
}
|
|
}
|
|
|
|
func ListToPushCommits(l *list.List) *PushCommits {
|
|
commits := make([]*PushCommit, 0)
|
|
var actEmail string
|
|
for e := l.Front(); e != nil; e = e.Next() {
|
|
commit := e.Value.(*git.Commit)
|
|
if actEmail == "" {
|
|
actEmail = commit.Committer.Email
|
|
}
|
|
commits = append(commits, CommitToPushCommit(commit))
|
|
}
|
|
return &PushCommits{l.Len(), commits, "", nil}
|
|
}
|
|
|
|
type PushUpdateOptions struct {
|
|
OldCommitID string
|
|
NewCommitID string
|
|
RefFullName string
|
|
PusherID int64
|
|
PusherName string
|
|
RepoUserName string
|
|
RepoName string
|
|
}
|
|
|
|
// PushUpdate must be called for any push actions in order to
|
|
// generates necessary push action history feeds.
|
|
func PushUpdate(opts PushUpdateOptions) (err error) {
|
|
isNewRef := opts.OldCommitID == git.EMPTY_SHA
|
|
isDelRef := opts.NewCommitID == git.EMPTY_SHA
|
|
if isNewRef && isDelRef {
|
|
return fmt.Errorf("Old and new revisions are both %s", git.EMPTY_SHA)
|
|
}
|
|
|
|
repoPath := RepoPath(opts.RepoUserName, opts.RepoName)
|
|
|
|
gitUpdate := exec.Command("git", "update-server-info")
|
|
gitUpdate.Dir = repoPath
|
|
if err = gitUpdate.Run(); err != nil {
|
|
return fmt.Errorf("Fail to call 'git update-server-info': %v", err)
|
|
}
|
|
|
|
if isDelRef {
|
|
log.Trace("Reference '%s' has been deleted from '%s/%s' by %s",
|
|
opts.RefFullName, opts.RepoUserName, opts.RepoName, opts.PusherName)
|
|
return nil
|
|
}
|
|
|
|
gitRepo, err := git.OpenRepository(repoPath)
|
|
if err != nil {
|
|
return fmt.Errorf("OpenRepository: %v", err)
|
|
}
|
|
|
|
owner, err := GetUserByName(opts.RepoUserName)
|
|
if err != nil {
|
|
return fmt.Errorf("GetUserByName: %v", err)
|
|
}
|
|
|
|
repo, err := GetRepositoryByName(owner.ID, opts.RepoName)
|
|
if err != nil {
|
|
return fmt.Errorf("GetRepositoryByName: %v", err)
|
|
}
|
|
|
|
// Push tags.
|
|
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
|
|
if err := CommitRepoAction(CommitRepoActionOptions{
|
|
PusherName: opts.PusherName,
|
|
RepoOwnerID: owner.ID,
|
|
RepoName: repo.Name,
|
|
RefFullName: opts.RefFullName,
|
|
OldCommitID: opts.OldCommitID,
|
|
NewCommitID: opts.NewCommitID,
|
|
Commits: &PushCommits{},
|
|
}); err != nil {
|
|
return fmt.Errorf("CommitRepoAction (tag): %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
|
|
if err != nil {
|
|
return fmt.Errorf("gitRepo.GetCommit: %v", err)
|
|
}
|
|
|
|
// Push new branch.
|
|
var l *list.List
|
|
if isNewRef {
|
|
l, err = newCommit.CommitsBeforeLimit(10)
|
|
if err != nil {
|
|
return fmt.Errorf("newCommit.CommitsBeforeLimit: %v", err)
|
|
}
|
|
} else {
|
|
l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID)
|
|
if err != nil {
|
|
return fmt.Errorf("newCommit.CommitsBeforeUntil: %v", err)
|
|
}
|
|
}
|
|
|
|
if err := CommitRepoAction(CommitRepoActionOptions{
|
|
PusherName: opts.PusherName,
|
|
RepoOwnerID: owner.ID,
|
|
RepoName: repo.Name,
|
|
RefFullName: opts.RefFullName,
|
|
OldCommitID: opts.OldCommitID,
|
|
NewCommitID: opts.NewCommitID,
|
|
Commits: ListToPushCommits(l),
|
|
}); err != nil {
|
|
return fmt.Errorf("CommitRepoAction (branch): %v", err)
|
|
}
|
|
return nil
|
|
}
|