mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-01 05:36:19 +01:00
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:
parent
0d80af649a
commit
1eedd983ea
8 changed files with 221 additions and 126 deletions
|
@ -0,0 +1 @@
|
||||||
|
65f1bf27bc3bf70f64657658635e66094edbcb4d
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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{}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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}}
|
||||||
|
|
Loading…
Reference in a new issue