Complete push webhooks (#2530)

* implemented missing 'delete' push webhooks

moreover created ActionDeleteBranch and ActionDeleteTag

* add CommitRepoAction tests for tag/branch creation/deletion

* fixed error where push webhook not called if is new branch or tag
removed unnecessary code

* moved prepare unit test environment into separate method to be used across unit tests

* add missing if clause in pushUpdate

Signed-off-by: David Schneiderbauer <dschneiderbauer@gmail.com>
This commit is contained in:
David Schneiderbauer 2017-09-21 09:43:26 +02:00 committed by Lauris BH
parent 0d80af649a
commit 1eedd983ea
8 changed files with 221 additions and 126 deletions

View file

@ -0,0 +1 @@
65f1bf27bc3bf70f64657658635e66094edbcb4d

View file

@ -46,6 +46,8 @@ const (
ActionReopenIssue // 13 ActionReopenIssue // 13
ActionClosePullRequest // 14 ActionClosePullRequest // 14
ActionReopenPullRequest // 15 ActionReopenPullRequest // 15
ActionDeleteTag // 16
ActionDeleteBranch // 17
) )
var ( var (
@ -554,6 +556,12 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
// Check it's tag push or branch. // Check it's tag push or branch.
if strings.HasPrefix(opts.RefFullName, git.TagPrefix) { if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
opType = ActionPushTag opType = ActionPushTag
if opts.NewCommitID == git.EmptySHA {
opType = ActionDeleteTag
}
opts.Commits = &PushCommits{}
} else if opts.NewCommitID == git.EmptySHA {
opType = ActionDeleteBranch
opts.Commits = &PushCommits{} opts.Commits = &PushCommits{}
} else { } else {
// if not the first commit, set the compare URL. // if not the first commit, set the compare URL.
@ -599,8 +607,60 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
apiRepo := repo.APIFormat(AccessModeNone) apiRepo := repo.APIFormat(AccessModeNone)
var shaSum string var shaSum string
var isHookEventPush = false
switch opType { switch opType {
case ActionCommitRepo: // Push case ActionCommitRepo: // Push
isHookEventPush = true
if isNewBranch {
gitRepo, err := git.OpenRepository(repo.RepoPath())
if err != nil {
log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err)
}
shaSum, err = gitRepo.GetBranchCommitID(refName)
if err != nil {
log.Error(4, "GetBranchCommitID[%s]: %v", opts.RefFullName, err)
}
if err = PrepareWebhooks(repo, HookEventCreate, &api.CreatePayload{
Ref: refName,
Sha: shaSum,
RefType: "branch",
Repo: apiRepo,
Sender: apiPusher,
}); err != nil {
return fmt.Errorf("PrepareWebhooks: %v", err)
}
}
case ActionDeleteBranch: // Delete Branch
isHookEventPush = true
case ActionPushTag: // Create
isHookEventPush = true
gitRepo, err := git.OpenRepository(repo.RepoPath())
if err != nil {
log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err)
}
shaSum, err = gitRepo.GetTagCommitID(refName)
if err != nil {
log.Error(4, "GetTagCommitID[%s]: %v", opts.RefFullName, err)
}
if err = PrepareWebhooks(repo, HookEventCreate, &api.CreatePayload{
Ref: refName,
Sha: shaSum,
RefType: "tag",
Repo: apiRepo,
Sender: apiPusher,
}); err != nil {
return fmt.Errorf("PrepareWebhooks: %v", err)
}
case ActionDeleteTag: // Delete Tag
isHookEventPush = true
}
if isHookEventPush {
if err = PrepareWebhooks(repo, HookEventPush, &api.PushPayload{ if err = PrepareWebhooks(repo, HookEventPush, &api.PushPayload{
Ref: opts.RefFullName, Ref: opts.RefFullName,
Before: opts.OldCommitID, Before: opts.OldCommitID,
@ -613,41 +673,6 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
}); err != nil { }); err != nil {
return fmt.Errorf("PrepareWebhooks: %v", err) return fmt.Errorf("PrepareWebhooks: %v", err)
} }
if isNewBranch {
gitRepo, err := git.OpenRepository(repo.RepoPath())
if err != nil {
log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err)
}
shaSum, err = gitRepo.GetBranchCommitID(refName)
if err != nil {
log.Error(4, "GetBranchCommitID[%s]: %v", opts.RefFullName, err)
}
return PrepareWebhooks(repo, HookEventCreate, &api.CreatePayload{
Ref: refName,
Sha: shaSum,
RefType: "branch",
Repo: apiRepo,
Sender: apiPusher,
})
}
case ActionPushTag: // Create
gitRepo, err := git.OpenRepository(repo.RepoPath())
if err != nil {
log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err)
}
shaSum, err = gitRepo.GetTagCommitID(refName)
if err != nil {
log.Error(4, "GetTagCommitID[%s]: %v", opts.RefFullName, err)
}
return PrepareWebhooks(repo, HookEventCreate, &api.CreatePayload{
Ref: refName,
Sha: shaSum,
RefType: "tag",
Repo: apiRepo,
Sender: apiPusher,
})
} }
return nil return nil

View file

@ -5,6 +5,7 @@ import (
"strings" "strings"
"testing" "testing"
"code.gitea.io/git"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -202,15 +203,30 @@ func TestUpdateIssuesCommit(t *testing.T) {
CheckConsistencyFor(t, &Action{}) CheckConsistencyFor(t, &Action{})
} }
func testCorrectRepoAction(t *testing.T, opts CommitRepoActionOptions, actionBean *Action) {
AssertNotExistsBean(t, actionBean)
assert.NoError(t, CommitRepoAction(opts))
AssertExistsAndLoadBean(t, actionBean)
CheckConsistencyFor(t, &Action{})
}
func TestCommitRepoAction(t *testing.T) { func TestCommitRepoAction(t *testing.T) {
assert.NoError(t, PrepareTestDatabase()) samples := []struct {
userID int64
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) repositoryID int64
repo := AssertExistsAndLoadBean(t, &Repository{ID: 2, OwnerID: user.ID}).(*Repository) commitRepoActionOptions CommitRepoActionOptions
repo.Owner = user action Action
}{
pushCommits := NewPushCommits() {
pushCommits.Commits = []*PushCommit{ userID: 2,
repositoryID: 2,
commitRepoActionOptions: CommitRepoActionOptions{
RefFullName: "refName",
OldCommitID: "oldCommitID",
NewCommitID: "newCommitID",
Commits: &PushCommits{
avatars: make(map[string]string),
Commits: []*PushCommit{
{ {
Sha1: "abcdef1", Sha1: "abcdef1",
CommitterEmail: "user2@example.com", CommitterEmail: "user2@example.com",
@ -227,30 +243,76 @@ func TestCommitRepoAction(t *testing.T) {
AuthorName: "User Two", AuthorName: "User Two",
Message: "message2", Message: "message2",
}, },
} },
pushCommits.Len = len(pushCommits.Commits) Len: 2,
},
actionBean := &Action{ },
action: Action{
OpType: ActionCommitRepo, OpType: ActionCommitRepo,
ActUserID: user.ID,
ActUser: user,
RepoID: repo.ID,
Repo: repo,
RefName: "refName", RefName: "refName",
IsPrivate: repo.IsPrivate, },
} },
AssertNotExistsBean(t, actionBean) {
assert.NoError(t, CommitRepoAction(CommitRepoActionOptions{ userID: 2,
PusherName: user.Name, repositoryID: 1,
RepoOwnerID: user.ID, commitRepoActionOptions: CommitRepoActionOptions{
RepoName: repo.Name, RefFullName: git.TagPrefix + "v1.1",
RefFullName: "refName", OldCommitID: git.EmptySHA,
OldCommitID: "oldCommitID",
NewCommitID: "newCommitID", NewCommitID: "newCommitID",
Commits: pushCommits, Commits: &PushCommits{},
})) },
AssertExistsAndLoadBean(t, actionBean) action: Action{
CheckConsistencyFor(t, &Action{}) OpType: ActionPushTag,
RefName: "v1.1",
},
},
{
userID: 2,
repositoryID: 1,
commitRepoActionOptions: CommitRepoActionOptions{
RefFullName: git.TagPrefix + "v1.1",
OldCommitID: "oldCommitID",
NewCommitID: git.EmptySHA,
Commits: &PushCommits{},
},
action: Action{
OpType: ActionDeleteTag,
RefName: "v1.1",
},
},
{
userID: 2,
repositoryID: 1,
commitRepoActionOptions: CommitRepoActionOptions{
RefFullName: git.BranchPrefix + "feature/1",
OldCommitID: "oldCommitID",
NewCommitID: git.EmptySHA,
Commits: &PushCommits{},
},
action: Action{
OpType: ActionDeleteBranch,
RefName: "feature/1",
},
},
}
for _, s := range samples {
prepareTestEnv(t)
user := AssertExistsAndLoadBean(t, &User{ID: s.userID}).(*User)
repo := AssertExistsAndLoadBean(t, &Repository{ID: s.repositoryID, OwnerID: user.ID}).(*Repository)
repo.Owner = user
s.commitRepoActionOptions.PusherName = user.Name
s.commitRepoActionOptions.RepoOwnerID = user.ID
s.commitRepoActionOptions.RepoName = repo.Name
s.action.ActUserID = user.ID
s.action.RepoID = repo.ID
s.action.IsPrivate = repo.IsPrivate
testCorrectRepoAction(t, s.commitRepoActionOptions, &s.action)
}
} }
func TestTransferRepoAction(t *testing.T) { func TestTransferRepoAction(t *testing.T) {

View file

@ -5,8 +5,12 @@
package models package models
import ( import (
"os"
"testing" "testing"
"code.gitea.io/gitea/modules/setting"
"github.com/Unknwon/com"
"github.com/go-xorm/core" "github.com/go-xorm/core"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -38,6 +42,12 @@ func PrepareTestDatabase() error {
return LoadFixtures() return LoadFixtures()
} }
func prepareTestEnv(t testing.TB) {
assert.NoError(t, PrepareTestDatabase())
assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
assert.NoError(t, com.CopyDir("../integrations/gitea-repositories-meta", setting.RepoRootPath))
}
type testCond struct { type testCond struct {
query interface{} query interface{}
args []interface{} args []interface{}

View file

@ -198,40 +198,26 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) {
return nil, fmt.Errorf("OpenRepository: %v", err) return nil, fmt.Errorf("OpenRepository: %v", err)
} }
if isDelRef {
// Tag has been deleted
if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
err = pushUpdateDeleteTag(repo, gitRepo, opts.RefFullName[len(git.TagPrefix):])
if err != nil {
return nil, fmt.Errorf("pushUpdateDeleteTag: %v", err)
}
}
log.GitLogger.Info("Reference '%s' has been deleted from '%s/%s' by %s",
opts.RefFullName, opts.RepoUserName, opts.RepoName, opts.PusherName)
return repo, nil
}
if err = repo.UpdateSize(); err != nil { if err = repo.UpdateSize(); err != nil {
log.Error(4, "Failed to update size for repository: %v", err) log.Error(4, "Failed to update size for repository: %v", err)
} }
// Push tags. var commits = &PushCommits{}
if strings.HasPrefix(opts.RefFullName, git.TagPrefix) { if strings.HasPrefix(opts.RefFullName, git.TagPrefix) {
pushUpdateAddTag(repo, gitRepo, opts.RefFullName[len(git.TagPrefix):]) // If is tag reference
if err := CommitRepoAction(CommitRepoActionOptions{ if isDelRef {
PusherName: opts.PusherName, err = pushUpdateDeleteTag(repo, gitRepo, opts.RefFullName[len(git.TagPrefix):])
RepoOwnerID: owner.ID, if err != nil {
RepoName: repo.Name, return nil, fmt.Errorf("pushUpdateDeleteTag: %v", err)
RefFullName: opts.RefFullName,
OldCommitID: opts.OldCommitID,
NewCommitID: opts.NewCommitID,
Commits: &PushCommits{},
}); err != nil {
return nil, fmt.Errorf("CommitRepoAction (tag): %v", err)
} }
return repo, nil } else {
err = pushUpdateAddTag(repo, gitRepo, opts.RefFullName[len(git.TagPrefix):])
if err != nil {
return nil, fmt.Errorf("pushUpdateAddTag: %v", err)
} }
}
} else if !isDelRef {
// If is branch reference
newCommit, err := gitRepo.GetCommit(opts.NewCommitID) newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
if err != nil { if err != nil {
return nil, fmt.Errorf("gitRepo.GetCommit: %v", err) return nil, fmt.Errorf("gitRepo.GetCommit: %v", err)
@ -251,6 +237,9 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) {
} }
} }
commits = ListToPushCommits(l)
}
if err := CommitRepoAction(CommitRepoActionOptions{ if err := CommitRepoAction(CommitRepoActionOptions{
PusherName: opts.PusherName, PusherName: opts.PusherName,
RepoOwnerID: owner.ID, RepoOwnerID: owner.ID,
@ -258,9 +247,9 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) {
RefFullName: opts.RefFullName, RefFullName: opts.RefFullName,
OldCommitID: opts.OldCommitID, OldCommitID: opts.OldCommitID,
NewCommitID: opts.NewCommitID, NewCommitID: opts.NewCommitID,
Commits: ListToPushCommits(l), Commits: commits,
}); err != nil { }); err != nil {
return nil, fmt.Errorf("CommitRepoAction (branch): %v", err) return nil, fmt.Errorf("CommitRepoAction: %v", err)
} }
return repo, nil return repo, nil
} }

View file

@ -294,7 +294,7 @@ func ActionIcon(opType models.ActionType) string {
switch opType { switch opType {
case models.ActionCreateRepo, models.ActionTransferRepo: case models.ActionCreateRepo, models.ActionTransferRepo:
return "repo" return "repo"
case models.ActionCommitRepo, models.ActionPushTag: case models.ActionCommitRepo, models.ActionPushTag, models.ActionDeleteTag, models.ActionDeleteBranch:
return "git-commit" return "git-commit"
case models.ActionCreateIssue: case models.ActionCreateIssue:
return "issue-opened" return "issue-opened"

View file

@ -1436,6 +1436,8 @@ comment_issue = `commented on issue <a href="%s/issues/%s">%s#%[2]s</a>`
merge_pull_request = `merged pull request <a href="%s/pulls/%s">%s#%[2]s</a>` merge_pull_request = `merged pull request <a href="%s/pulls/%s">%s#%[2]s</a>`
transfer_repo = transferred repository <code>%s</code> to <a href="%s">%s</a> transfer_repo = transferred repository <code>%s</code> to <a href="%s">%s</a>
push_tag = pushed tag <a href="%s/src/%s">%[2]s</a> to <a href="%[1]s">%[3]s</a> push_tag = pushed tag <a href="%s/src/%s">%[2]s</a> to <a href="%[1]s">%[3]s</a>
delete_tag = deleted tag %[2]s from <a href="%[1]s">%[3]s</a>
delete_branch = deleted branch %[2]s from <a href="%[1]s">%[3]s</a>
compare_commits = Compare %d commits compare_commits = Compare %d commits
[tool] [tool]

View file

@ -43,6 +43,12 @@
{{else if eq .GetOpType 15}} {{else if eq .GetOpType 15}}
{{ $index := index .GetIssueInfos 0}} {{ $index := index .GetIssueInfos 0}}
{{$.i18n.Tr "action.reopen_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}} {{$.i18n.Tr "action.reopen_pull_request" .GetRepoLink $index .ShortRepoPath | Str2html}}
{{else if eq .GetOpType 16}}
{{ $index := index .GetIssueInfos 0}}
{{$.i18n.Tr "action.delete_tag" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}}
{{else if eq .GetOpType 17}}
{{ $index := index .GetIssueInfos 0}}
{{$.i18n.Tr "action.delete_branch" .GetRepoLink .GetBranch .ShortRepoPath | Str2html}}
{{end}} {{end}}
</p> </p>
{{if eq .GetOpType 5}} {{if eq .GetOpType 5}}