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
 | ||||
| 	ActionClosePullRequest                        // 14
 | ||||
| 	ActionReopenPullRequest                       // 15
 | ||||
| 	ActionDeleteTag                               // 16
 | ||||
| 	ActionDeleteBranch                            // 17
 | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
|  | @ -554,6 +556,12 @@ func CommitRepoAction(opts CommitRepoActionOptions) error { | |||
| 	// Check it's tag push or branch.
 | ||||
| 	if strings.HasPrefix(opts.RefFullName, git.TagPrefix) { | ||||
| 		opType = ActionPushTag | ||||
| 		if opts.NewCommitID == git.EmptySHA { | ||||
| 			opType = ActionDeleteTag | ||||
| 		} | ||||
| 		opts.Commits = &PushCommits{} | ||||
| 	} else if opts.NewCommitID == git.EmptySHA { | ||||
| 		opType = ActionDeleteBranch | ||||
| 		opts.Commits = &PushCommits{} | ||||
| 	} else { | ||||
| 		// if not the first commit, set the compare URL.
 | ||||
|  | @ -599,8 +607,60 @@ func CommitRepoAction(opts CommitRepoActionOptions) error { | |||
| 	apiRepo := repo.APIFormat(AccessModeNone) | ||||
| 
 | ||||
| 	var shaSum string | ||||
| 	var isHookEventPush = false | ||||
| 	switch opType { | ||||
| 	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{ | ||||
| 			Ref:        opts.RefFullName, | ||||
| 			Before:     opts.OldCommitID, | ||||
|  | @ -613,41 +673,6 @@ func CommitRepoAction(opts CommitRepoActionOptions) error { | |||
| 		}); err != nil { | ||||
| 			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 | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ import ( | |||
| 	"strings" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"code.gitea.io/git" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | @ -202,15 +203,30 @@ func TestUpdateIssuesCommit(t *testing.T) { | |||
| 	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) { | ||||
| 	assert.NoError(t, PrepareTestDatabase()) | ||||
| 
 | ||||
| 	user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) | ||||
| 	repo := AssertExistsAndLoadBean(t, &Repository{ID: 2, OwnerID: user.ID}).(*Repository) | ||||
| 	repo.Owner = user | ||||
| 
 | ||||
| 	pushCommits := NewPushCommits() | ||||
| 	pushCommits.Commits = []*PushCommit{ | ||||
| 	samples := []struct { | ||||
| 		userID                  int64 | ||||
| 		repositoryID            int64 | ||||
| 		commitRepoActionOptions CommitRepoActionOptions | ||||
| 		action                  Action | ||||
| 	}{ | ||||
| 		{ | ||||
| 			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", | ||||
|  | @ -227,30 +243,76 @@ func TestCommitRepoAction(t *testing.T) { | |||
| 							AuthorName:     "User Two", | ||||
| 							Message:        "message2", | ||||
| 						}, | ||||
| 	} | ||||
| 	pushCommits.Len = len(pushCommits.Commits) | ||||
| 
 | ||||
| 	actionBean := &Action{ | ||||
| 					}, | ||||
| 					Len: 2, | ||||
| 				}, | ||||
| 			}, | ||||
| 			action: Action{ | ||||
| 				OpType:  ActionCommitRepo, | ||||
| 		ActUserID: user.ID, | ||||
| 		ActUser:   user, | ||||
| 		RepoID:    repo.ID, | ||||
| 		Repo:      repo, | ||||
| 				RefName: "refName", | ||||
| 		IsPrivate: repo.IsPrivate, | ||||
| 	} | ||||
| 	AssertNotExistsBean(t, actionBean) | ||||
| 	assert.NoError(t, CommitRepoAction(CommitRepoActionOptions{ | ||||
| 		PusherName:  user.Name, | ||||
| 		RepoOwnerID: user.ID, | ||||
| 		RepoName:    repo.Name, | ||||
| 		RefFullName: "refName", | ||||
| 		OldCommitID: "oldCommitID", | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			userID:       2, | ||||
| 			repositoryID: 1, | ||||
| 			commitRepoActionOptions: CommitRepoActionOptions{ | ||||
| 				RefFullName: git.TagPrefix + "v1.1", | ||||
| 				OldCommitID: git.EmptySHA, | ||||
| 				NewCommitID: "newCommitID", | ||||
| 		Commits:     pushCommits, | ||||
| 	})) | ||||
| 	AssertExistsAndLoadBean(t, actionBean) | ||||
| 	CheckConsistencyFor(t, &Action{}) | ||||
| 				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", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	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) { | ||||
|  |  | |||
|  | @ -5,8 +5,12 @@ | |||
| package models | ||||
| 
 | ||||
| import ( | ||||
| 	"os" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 
 | ||||
| 	"github.com/Unknwon/com" | ||||
| 	"github.com/go-xorm/core" | ||||
| 	"github.com/go-xorm/xorm" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | @ -38,6 +42,12 @@ func PrepareTestDatabase() error { | |||
| 	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 { | ||||
| 	query interface{} | ||||
| 	args  []interface{} | ||||
|  |  | |||
|  | @ -198,40 +198,26 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) { | |||
| 		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 { | ||||
| 		log.Error(4, "Failed to update size for repository: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Push tags.
 | ||||
| 	var commits = &PushCommits{} | ||||
| 	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) | ||||
| 			} | ||||
| 		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) | ||||
| 		if err != nil { | ||||
| 			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{ | ||||
| 		PusherName:  opts.PusherName, | ||||
| 		RepoOwnerID: owner.ID, | ||||
|  | @ -258,9 +247,9 @@ func pushUpdate(opts PushUpdateOptions) (repo *Repository, err error) { | |||
| 		RefFullName: opts.RefFullName, | ||||
| 		OldCommitID: opts.OldCommitID, | ||||
| 		NewCommitID: opts.NewCommitID, | ||||
| 		Commits:     ListToPushCommits(l), | ||||
| 		Commits:     commits, | ||||
| 	}); err != nil { | ||||
| 		return nil, fmt.Errorf("CommitRepoAction (branch): %v", err) | ||||
| 		return nil, fmt.Errorf("CommitRepoAction: %v", err) | ||||
| 	} | ||||
| 	return repo, nil | ||||
| } | ||||
|  |  | |||
|  | @ -294,7 +294,7 @@ func ActionIcon(opType models.ActionType) string { | |||
| 	switch opType { | ||||
| 	case models.ActionCreateRepo, models.ActionTransferRepo: | ||||
| 		return "repo" | ||||
| 	case models.ActionCommitRepo, models.ActionPushTag: | ||||
| 	case models.ActionCommitRepo, models.ActionPushTag, models.ActionDeleteTag, models.ActionDeleteBranch: | ||||
| 		return "git-commit" | ||||
| 	case models.ActionCreateIssue: | ||||
| 		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>` | ||||
| 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> | ||||
| 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 | ||||
| 
 | ||||
| [tool] | ||||
|  |  | |||
|  | @ -43,6 +43,12 @@ | |||
| 						{{else if eq .GetOpType 15}} | ||||
| 							{{ $index := index .GetIssueInfos 0}} | ||||
| 							{{$.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}} | ||||
| 					</p> | ||||
| 					{{if eq .GetOpType 5}} | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue