Batch hook pre- and post-receive calls (#8602)
* make notifyWatchers work on multiple actions * more efficient multiple notifyWatchers * Make CommitRepoAction take advantage of multiple actions * Batch post and pre-receive results * Set batch to 30 * Auto adjust timeout & add logging * adjust processing message * Add some messages to pre-receive * Make any non-200 status code from pre-receive an error * Add missing hookPrintResults * Remove shortcut for single action * mistaken merge fix * oops * Move master branch to the front * If repo was empty and the master branch is pushed ensure that that is set as the default branch * fixup * fixup * Missed HookOptions in setdefaultbranch * Batch PushUpdateAddTag and PushUpdateDelTag Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
parent
114d474f02
commit
7bfb83e064
10 changed files with 1063 additions and 440 deletions
|
@ -164,68 +164,111 @@ func (repo *Repository) GetWatchers(page int) ([]*User, error) {
|
|||
return users, sess.Find(&users)
|
||||
}
|
||||
|
||||
func notifyWatchers(e Engine, act *Action) error {
|
||||
// Add feeds for user self and all watchers.
|
||||
watches, err := getWatchers(e, act.RepoID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get watchers: %v", err)
|
||||
}
|
||||
func notifyWatchers(e Engine, actions ...*Action) error {
|
||||
var watchers []*Watch
|
||||
var repo *Repository
|
||||
var err error
|
||||
var permCode []bool
|
||||
var permIssue []bool
|
||||
var permPR []bool
|
||||
|
||||
// Add feed for actioner.
|
||||
act.UserID = act.ActUserID
|
||||
if _, err = e.InsertOne(act); err != nil {
|
||||
return fmt.Errorf("insert new actioner: %v", err)
|
||||
}
|
||||
for _, act := range actions {
|
||||
repoChanged := repo == nil || repo.ID != act.RepoID
|
||||
|
||||
act.loadRepo()
|
||||
// check repo owner exist.
|
||||
if err := act.Repo.getOwner(e); err != nil {
|
||||
return fmt.Errorf("can't get repo owner: %v", err)
|
||||
}
|
||||
if repoChanged {
|
||||
// Add feeds for user self and all watchers.
|
||||
watchers, err = getWatchers(e, act.RepoID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get watchers: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Add feed for organization
|
||||
if act.Repo.Owner.IsOrganization() && act.ActUserID != act.Repo.Owner.ID {
|
||||
act.ID = 0
|
||||
act.UserID = act.Repo.Owner.ID
|
||||
// Add feed for actioner.
|
||||
act.UserID = act.ActUserID
|
||||
if _, err = e.InsertOne(act); err != nil {
|
||||
return fmt.Errorf("insert new actioner: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := range watches {
|
||||
if act.ActUserID == watches[i].UserID {
|
||||
continue
|
||||
if repoChanged {
|
||||
act.loadRepo()
|
||||
repo = act.Repo
|
||||
|
||||
// check repo owner exist.
|
||||
if err := act.Repo.getOwner(e); err != nil {
|
||||
return fmt.Errorf("can't get repo owner: %v", err)
|
||||
}
|
||||
} else if act.Repo == nil {
|
||||
act.Repo = repo
|
||||
}
|
||||
|
||||
act.ID = 0
|
||||
act.UserID = watches[i].UserID
|
||||
act.Repo.Units = nil
|
||||
|
||||
switch act.OpType {
|
||||
case ActionCommitRepo, ActionPushTag, ActionDeleteTag, ActionDeleteBranch:
|
||||
if !act.Repo.checkUnitUser(e, act.UserID, false, UnitTypeCode) {
|
||||
continue
|
||||
}
|
||||
case ActionCreateIssue, ActionCommentIssue, ActionCloseIssue, ActionReopenIssue:
|
||||
if !act.Repo.checkUnitUser(e, act.UserID, false, UnitTypeIssues) {
|
||||
continue
|
||||
}
|
||||
case ActionCreatePullRequest, ActionCommentPull, ActionMergePullRequest, ActionClosePullRequest, ActionReopenPullRequest:
|
||||
if !act.Repo.checkUnitUser(e, act.UserID, false, UnitTypePullRequests) {
|
||||
continue
|
||||
// Add feed for organization
|
||||
if act.Repo.Owner.IsOrganization() && act.ActUserID != act.Repo.Owner.ID {
|
||||
act.ID = 0
|
||||
act.UserID = act.Repo.Owner.ID
|
||||
if _, err = e.InsertOne(act); err != nil {
|
||||
return fmt.Errorf("insert new actioner: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = e.InsertOne(act); err != nil {
|
||||
return fmt.Errorf("insert new action: %v", err)
|
||||
if repoChanged {
|
||||
permCode = make([]bool, len(watchers))
|
||||
permIssue = make([]bool, len(watchers))
|
||||
permPR = make([]bool, len(watchers))
|
||||
for i, watcher := range watchers {
|
||||
user, err := getUserByID(e, watcher.UserID)
|
||||
if err != nil {
|
||||
permCode[i] = false
|
||||
permIssue[i] = false
|
||||
permPR[i] = false
|
||||
continue
|
||||
}
|
||||
perm, err := getUserRepoPermission(e, repo, user)
|
||||
if err != nil {
|
||||
permCode[i] = false
|
||||
permIssue[i] = false
|
||||
permPR[i] = false
|
||||
continue
|
||||
}
|
||||
permCode[i] = perm.CanRead(UnitTypeCode)
|
||||
permIssue[i] = perm.CanRead(UnitTypeIssues)
|
||||
permPR[i] = perm.CanRead(UnitTypePullRequests)
|
||||
}
|
||||
}
|
||||
|
||||
for i, watcher := range watchers {
|
||||
if act.ActUserID == watcher.UserID {
|
||||
continue
|
||||
}
|
||||
act.ID = 0
|
||||
act.UserID = watcher.UserID
|
||||
act.Repo.Units = nil
|
||||
|
||||
switch act.OpType {
|
||||
case ActionCommitRepo, ActionPushTag, ActionDeleteTag, ActionDeleteBranch:
|
||||
if !permCode[i] {
|
||||
continue
|
||||
}
|
||||
case ActionCreateIssue, ActionCommentIssue, ActionCloseIssue, ActionReopenIssue:
|
||||
if !permIssue[i] {
|
||||
continue
|
||||
}
|
||||
case ActionCreatePullRequest, ActionCommentPull, ActionMergePullRequest, ActionClosePullRequest, ActionReopenPullRequest:
|
||||
if !permPR[i] {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = e.InsertOne(act); err != nil {
|
||||
return fmt.Errorf("insert new action: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotifyWatchers creates batch of actions for every watcher.
|
||||
func NotifyWatchers(act *Action) error {
|
||||
return notifyWatchers(x, act)
|
||||
func NotifyWatchers(actions ...*Action) error {
|
||||
return notifyWatchers(x, actions...)
|
||||
}
|
||||
|
||||
// NotifyWatchersActions creates batch of actions for every watcher.
|
||||
|
|
179
models/update.go
179
models/update.go
|
@ -53,6 +53,66 @@ func ListToPushCommits(l *list.List) *PushCommits {
|
|||
return &PushCommits{l.Len(), commits, "", make(map[string]string), make(map[string]*User)}
|
||||
}
|
||||
|
||||
// PushUpdateAddDeleteTags updates a number of added and delete tags
|
||||
func PushUpdateAddDeleteTags(repo *Repository, gitRepo *git.Repository, addTags, delTags []string) error {
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return fmt.Errorf("Unable to begin sess in PushUpdateDeleteTags: %v", err)
|
||||
}
|
||||
if err := pushUpdateDeleteTags(sess, repo, delTags); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := pushUpdateAddTags(sess, repo, gitRepo, addTags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
// PushUpdateDeleteTags updates a number of delete tags
|
||||
func PushUpdateDeleteTags(repo *Repository, tags []string) error {
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return fmt.Errorf("Unable to begin sess in PushUpdateDeleteTags: %v", err)
|
||||
}
|
||||
if err := pushUpdateDeleteTags(sess, repo, tags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func pushUpdateDeleteTags(e Engine, repo *Repository, tags []string) error {
|
||||
if len(tags) == 0 {
|
||||
return nil
|
||||
}
|
||||
lowerTags := make([]string, 0, len(tags))
|
||||
for _, tag := range tags {
|
||||
lowerTags = append(lowerTags, strings.ToLower(tag))
|
||||
}
|
||||
|
||||
if _, err := e.
|
||||
Where("repo_id = ? AND is_tag = ?", repo.ID, true).
|
||||
In("lower_tag_name", lowerTags).
|
||||
Delete(new(Release)); err != nil {
|
||||
return fmt.Errorf("Delete: %v", err)
|
||||
}
|
||||
|
||||
if _, err := e.
|
||||
Where("repo_id = ? AND is_tag = ?", repo.ID, false).
|
||||
In("lower_tag_name", lowerTags).
|
||||
SetExpr("is_draft", true).
|
||||
SetExpr("num_commits", 0).
|
||||
SetExpr("sha1", "").
|
||||
Update(new(Release)); err != nil {
|
||||
return fmt.Errorf("Update: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PushUpdateDeleteTag must be called for any push actions to delete tag
|
||||
func PushUpdateDeleteTag(repo *Repository, tagName string) error {
|
||||
rel, err := GetRelease(repo.ID, tagName)
|
||||
|
@ -78,6 +138,125 @@ func PushUpdateDeleteTag(repo *Repository, tagName string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// PushUpdateAddTags updates a number of add tags
|
||||
func PushUpdateAddTags(repo *Repository, gitRepo *git.Repository, tags []string) error {
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return fmt.Errorf("Unable to begin sess in PushUpdateAddTags: %v", err)
|
||||
}
|
||||
if err := pushUpdateAddTags(sess, repo, gitRepo, tags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
func pushUpdateAddTags(e Engine, repo *Repository, gitRepo *git.Repository, tags []string) error {
|
||||
if len(tags) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
lowerTags := make([]string, 0, len(tags))
|
||||
for _, tag := range tags {
|
||||
lowerTags = append(lowerTags, strings.ToLower(tag))
|
||||
}
|
||||
|
||||
releases := make([]Release, 0, len(tags))
|
||||
if err := e.Where("repo_id = ?", repo.ID).
|
||||
In("lower_tag_name", lowerTags).Find(&releases); err != nil {
|
||||
return fmt.Errorf("GetRelease: %v", err)
|
||||
}
|
||||
relMap := make(map[string]*Release)
|
||||
for _, rel := range releases {
|
||||
relMap[rel.LowerTagName] = &rel
|
||||
}
|
||||
|
||||
newReleases := make([]*Release, 0, len(lowerTags)-len(relMap))
|
||||
|
||||
emailToUser := make(map[string]*User)
|
||||
|
||||
for i, lowerTag := range lowerTags {
|
||||
tag, err := gitRepo.GetTag(tags[i])
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetTag: %v", err)
|
||||
}
|
||||
commit, err := tag.Commit()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Commit: %v", err)
|
||||
}
|
||||
|
||||
sig := tag.Tagger
|
||||
if sig == nil {
|
||||
sig = commit.Author
|
||||
}
|
||||
if sig == nil {
|
||||
sig = commit.Committer
|
||||
}
|
||||
var author *User
|
||||
var createdAt = time.Unix(1, 0)
|
||||
|
||||
if sig != nil {
|
||||
var ok bool
|
||||
author, ok = emailToUser[sig.Email]
|
||||
if !ok {
|
||||
author, err = GetUserByEmail(sig.Email)
|
||||
if err != nil && !IsErrUserNotExist(err) {
|
||||
return fmt.Errorf("GetUserByEmail: %v", err)
|
||||
}
|
||||
}
|
||||
createdAt = sig.When
|
||||
}
|
||||
|
||||
commitsCount, err := commit.CommitsCount()
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsCount: %v", err)
|
||||
}
|
||||
|
||||
rel, has := relMap[lowerTag]
|
||||
|
||||
if !has {
|
||||
rel = &Release{
|
||||
RepoID: repo.ID,
|
||||
Title: "",
|
||||
TagName: tags[i],
|
||||
LowerTagName: lowerTag,
|
||||
Target: "",
|
||||
Sha1: commit.ID.String(),
|
||||
NumCommits: commitsCount,
|
||||
Note: "",
|
||||
IsDraft: false,
|
||||
IsPrerelease: false,
|
||||
IsTag: true,
|
||||
CreatedUnix: timeutil.TimeStamp(createdAt.Unix()),
|
||||
}
|
||||
if author != nil {
|
||||
rel.PublisherID = author.ID
|
||||
}
|
||||
|
||||
newReleases = append(newReleases, rel)
|
||||
} else {
|
||||
rel.Sha1 = commit.ID.String()
|
||||
rel.CreatedUnix = timeutil.TimeStamp(createdAt.Unix())
|
||||
rel.NumCommits = commitsCount
|
||||
rel.IsDraft = false
|
||||
if rel.IsTag && author != nil {
|
||||
rel.PublisherID = author.ID
|
||||
}
|
||||
if _, err = e.ID(rel.ID).AllCols().Update(rel); err != nil {
|
||||
return fmt.Errorf("Update: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(newReleases) > 0 {
|
||||
if _, err := e.Insert(newReleases); err != nil {
|
||||
return fmt.Errorf("Insert: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PushUpdateAddTag must be called for any push actions to add tag
|
||||
func PushUpdateAddTag(repo *Repository, gitRepo *git.Repository, tagName string) error {
|
||||
rel, err := GetRelease(repo.ID, tagName)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue