* 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>tags/v1.21.12.1
| @@ -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,40 +607,38 @@ 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 | ||||
| if err = PrepareWebhooks(repo, HookEventPush, &api.PushPayload{ | |||||
| Ref: opts.RefFullName, | |||||
| Before: opts.OldCommitID, | |||||
| After: opts.NewCommitID, | |||||
| CompareURL: setting.AppURL + opts.Commits.CompareURL, | |||||
| Commits: opts.Commits.ToAPIPayloadCommits(repo.HTMLURL()), | |||||
| Repo: apiRepo, | |||||
| Pusher: apiPusher, | |||||
| Sender: apiPusher, | |||||
| }); err != nil { | |||||
| return fmt.Errorf("PrepareWebhooks: %v", err) | |||||
| } | |||||
| isHookEventPush = true | |||||
| if isNewBranch { | if isNewBranch { | ||||
| gitRepo, err := git.OpenRepository(repo.RepoPath()) | gitRepo, err := git.OpenRepository(repo.RepoPath()) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err) | log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err) | ||||
| } | } | ||||
| shaSum, err = gitRepo.GetBranchCommitID(refName) | shaSum, err = gitRepo.GetBranchCommitID(refName) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error(4, "GetBranchCommitID[%s]: %v", opts.RefFullName, err) | log.Error(4, "GetBranchCommitID[%s]: %v", opts.RefFullName, err) | ||||
| } | } | ||||
| return PrepareWebhooks(repo, HookEventCreate, &api.CreatePayload{ | |||||
| if err = PrepareWebhooks(repo, HookEventCreate, &api.CreatePayload{ | |||||
| Ref: refName, | Ref: refName, | ||||
| Sha: shaSum, | Sha: shaSum, | ||||
| RefType: "branch", | RefType: "branch", | ||||
| Repo: apiRepo, | Repo: apiRepo, | ||||
| Sender: apiPusher, | Sender: apiPusher, | ||||
| }) | |||||
| }); err != nil { | |||||
| return fmt.Errorf("PrepareWebhooks: %v", err) | |||||
| } | |||||
| } | } | ||||
| case ActionDeleteBranch: // Delete Branch | |||||
| isHookEventPush = true | |||||
| case ActionPushTag: // Create | case ActionPushTag: // Create | ||||
| isHookEventPush = true | |||||
| gitRepo, err := git.OpenRepository(repo.RepoPath()) | gitRepo, err := git.OpenRepository(repo.RepoPath()) | ||||
| if err != nil { | if err != nil { | ||||
| log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err) | log.Error(4, "OpenRepository[%s]: %v", repo.RepoPath(), err) | ||||
| @@ -641,13 +647,32 @@ func CommitRepoAction(opts CommitRepoActionOptions) error { | |||||
| if err != nil { | if err != nil { | ||||
| log.Error(4, "GetTagCommitID[%s]: %v", opts.RefFullName, err) | log.Error(4, "GetTagCommitID[%s]: %v", opts.RefFullName, err) | ||||
| } | } | ||||
| return PrepareWebhooks(repo, HookEventCreate, &api.CreatePayload{ | |||||
| if err = PrepareWebhooks(repo, HookEventCreate, &api.CreatePayload{ | |||||
| Ref: refName, | Ref: refName, | ||||
| Sha: shaSum, | Sha: shaSum, | ||||
| RefType: "tag", | RefType: "tag", | ||||
| Repo: apiRepo, | Repo: apiRepo, | ||||
| Sender: apiPusher, | 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{ | |||||
| Ref: opts.RefFullName, | |||||
| Before: opts.OldCommitID, | |||||
| After: opts.NewCommitID, | |||||
| CompareURL: setting.AppURL + opts.Commits.CompareURL, | |||||
| Commits: opts.Commits.ToAPIPayloadCommits(repo.HTMLURL()), | |||||
| Repo: apiRepo, | |||||
| Pusher: apiPusher, | |||||
| Sender: apiPusher, | |||||
| }); err != nil { | |||||
| return fmt.Errorf("PrepareWebhooks: %v", err) | |||||
| } | |||||
| } | } | ||||
| 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,55 +203,116 @@ func TestUpdateIssuesCommit(t *testing.T) { | |||||
| CheckConsistencyFor(t, &Action{}) | CheckConsistencyFor(t, &Action{}) | ||||
| } | } | ||||
| func TestCommitRepoAction(t *testing.T) { | |||||
| assert.NoError(t, PrepareTestDatabase()) | |||||
| user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) | |||||
| repo := AssertExistsAndLoadBean(t, &Repository{ID: 2, OwnerID: user.ID}).(*Repository) | |||||
| repo.Owner = user | |||||
| func testCorrectRepoAction(t *testing.T, opts CommitRepoActionOptions, actionBean *Action) { | |||||
| AssertNotExistsBean(t, actionBean) | |||||
| assert.NoError(t, CommitRepoAction(opts)) | |||||
| AssertExistsAndLoadBean(t, actionBean) | |||||
| CheckConsistencyFor(t, &Action{}) | |||||
| } | |||||
| pushCommits := NewPushCommits() | |||||
| pushCommits.Commits = []*PushCommit{ | |||||
| func TestCommitRepoAction(t *testing.T) { | |||||
| samples := []struct { | |||||
| userID int64 | |||||
| repositoryID int64 | |||||
| commitRepoActionOptions CommitRepoActionOptions | |||||
| action Action | |||||
| }{ | |||||
| { | { | ||||
| Sha1: "abcdef1", | |||||
| CommitterEmail: "user2@example.com", | |||||
| CommitterName: "User Two", | |||||
| AuthorEmail: "user4@example.com", | |||||
| AuthorName: "User Four", | |||||
| Message: "message1", | |||||
| userID: 2, | |||||
| repositoryID: 2, | |||||
| commitRepoActionOptions: CommitRepoActionOptions{ | |||||
| RefFullName: "refName", | |||||
| OldCommitID: "oldCommitID", | |||||
| NewCommitID: "newCommitID", | |||||
| Commits: &PushCommits{ | |||||
| avatars: make(map[string]string), | |||||
| Commits: []*PushCommit{ | |||||
| { | |||||
| Sha1: "abcdef1", | |||||
| CommitterEmail: "user2@example.com", | |||||
| CommitterName: "User Two", | |||||
| AuthorEmail: "user4@example.com", | |||||
| AuthorName: "User Four", | |||||
| Message: "message1", | |||||
| }, | |||||
| { | |||||
| Sha1: "abcdef2", | |||||
| CommitterEmail: "user2@example.com", | |||||
| CommitterName: "User Two", | |||||
| AuthorEmail: "user2@example.com", | |||||
| AuthorName: "User Two", | |||||
| Message: "message2", | |||||
| }, | |||||
| }, | |||||
| Len: 2, | |||||
| }, | |||||
| }, | |||||
| action: Action{ | |||||
| OpType: ActionCommitRepo, | |||||
| RefName: "refName", | |||||
| }, | |||||
| }, | }, | ||||
| { | { | ||||
| Sha1: "abcdef2", | |||||
| CommitterEmail: "user2@example.com", | |||||
| CommitterName: "User Two", | |||||
| AuthorEmail: "user2@example.com", | |||||
| AuthorName: "User Two", | |||||
| Message: "message2", | |||||
| userID: 2, | |||||
| repositoryID: 1, | |||||
| commitRepoActionOptions: CommitRepoActionOptions{ | |||||
| RefFullName: git.TagPrefix + "v1.1", | |||||
| OldCommitID: git.EmptySHA, | |||||
| NewCommitID: "newCommitID", | |||||
| Commits: &PushCommits{}, | |||||
| }, | |||||
| action: 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", | |||||
| }, | |||||
| }, | }, | ||||
| } | } | ||||
| pushCommits.Len = len(pushCommits.Commits) | |||||
| actionBean := &Action{ | |||||
| OpType: ActionCommitRepo, | |||||
| ActUserID: user.ID, | |||||
| ActUser: user, | |||||
| RepoID: repo.ID, | |||||
| Repo: repo, | |||||
| RefName: "refName", | |||||
| IsPrivate: repo.IsPrivate, | |||||
| 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) | |||||
| } | } | ||||
| AssertNotExistsBean(t, actionBean) | |||||
| assert.NoError(t, CommitRepoAction(CommitRepoActionOptions{ | |||||
| PusherName: user.Name, | |||||
| RepoOwnerID: user.ID, | |||||
| RepoName: repo.Name, | |||||
| RefFullName: "refName", | |||||
| OldCommitID: "oldCommitID", | |||||
| NewCommitID: "newCommitID", | |||||
| Commits: pushCommits, | |||||
| })) | |||||
| AssertExistsAndLoadBean(t, actionBean) | |||||
| CheckConsistencyFor(t, &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,57 +198,46 @@ 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 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 nil, fmt.Errorf("CommitRepoAction (tag): %v", err) | |||||
| // If is tag reference | |||||
| if isDelRef { | |||||
| err = pushUpdateDeleteTag(repo, gitRepo, opts.RefFullName[len(git.TagPrefix):]) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("pushUpdateDeleteTag: %v", err) | |||||
| } | |||||
| } else { | |||||
| err = pushUpdateAddTag(repo, gitRepo, opts.RefFullName[len(git.TagPrefix):]) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("pushUpdateAddTag: %v", err) | |||||
| } | |||||
| } | } | ||||
| return repo, nil | |||||
| } | |||||
| newCommit, err := gitRepo.GetCommit(opts.NewCommitID) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("gitRepo.GetCommit: %v", err) | |||||
| } | |||||
| // Push new branch. | |||||
| var l *list.List | |||||
| if isNewRef { | |||||
| l, err = newCommit.CommitsBeforeLimit(10) | |||||
| } else if !isDelRef { | |||||
| // If is branch reference | |||||
| newCommit, err := gitRepo.GetCommit(opts.NewCommitID) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, fmt.Errorf("newCommit.CommitsBeforeLimit: %v", err) | |||||
| return nil, fmt.Errorf("gitRepo.GetCommit: %v", err) | |||||
| } | } | ||||
| } else { | |||||
| l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("newCommit.CommitsBeforeUntil: %v", err) | |||||
| // Push new branch. | |||||
| var l *list.List | |||||
| if isNewRef { | |||||
| l, err = newCommit.CommitsBeforeLimit(10) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("newCommit.CommitsBeforeLimit: %v", err) | |||||
| } | |||||
| } else { | |||||
| l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("newCommit.CommitsBeforeUntil: %v", err) | |||||
| } | |||||
| } | } | ||||
| commits = ListToPushCommits(l) | |||||
| } | } | ||||
| if err := CommitRepoAction(CommitRepoActionOptions{ | if err := CommitRepoAction(CommitRepoActionOptions{ | ||||
| @@ -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}} | ||||