Skip to content

Commit 5095cce

Browse files
committed
Webhooks for repo creation/deletion
1 parent edc817a commit 5095cce

File tree

14 files changed

+94
-37
lines changed

14 files changed

+94
-37
lines changed

models/repo.go

+31-11
Original file line numberDiff line numberDiff line change
@@ -835,8 +835,8 @@ func wikiRemoteURL(remote string) string {
835835
}
836836

837837
// MigrateRepository migrates a existing repository from other project hosting.
838-
func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
839-
repo, err := CreateRepository(u, CreateRepoOptions{
838+
func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, error) {
839+
repo, err := CreateRepository(doer, u, CreateRepoOptions{
840840
Name: opts.Name,
841841
Description: opts.Description,
842842
IsPrivate: opts.IsPrivate,
@@ -1202,7 +1202,7 @@ func IsUsableRepoName(name string) error {
12021202
return isUsableName(reservedRepoNames, reservedRepoPatterns, name)
12031203
}
12041204

1205-
func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) {
1205+
func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err error) {
12061206
if err = IsUsableRepoName(repo.Name); err != nil {
12071207
return err
12081208
}
@@ -1249,7 +1249,15 @@ func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) {
12491249
return fmt.Errorf("getOwnerTeam: %v", err)
12501250
} else if err = t.addRepository(e, repo); err != nil {
12511251
return fmt.Errorf("addRepository: %v", err)
1252+
} else if err = prepareWebhooks(e, repo, HookEventRepository, &api.RepositoryPayload{
1253+
Action: api.HookRepoCreated,
1254+
Repository: repo.APIFormat(AccessModeOwner),
1255+
Organization: u.APIFormat(),
1256+
Sender: doer.APIFormat(),
1257+
}); err != nil {
1258+
return fmt.Errorf("prepareWebhooks: %v", err)
12521259
}
1260+
go HookQueue.Add(repo.ID)
12531261
} else {
12541262
// Organization automatically called this in addRepository method.
12551263
if err = repo.recalculateAccesses(e); err != nil {
@@ -1266,8 +1274,8 @@ func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) {
12661274
return nil
12671275
}
12681276

1269-
// CreateRepository creates a repository for given user or organization.
1270-
func CreateRepository(u *User, opts CreateRepoOptions) (_ *Repository, err error) {
1277+
// CreateRepository creates a repository for the user/organization u.
1278+
func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err error) {
12711279
if !u.CanCreateRepo() {
12721280
return nil, ErrReachLimitOfRepo{u.MaxRepoCreation}
12731281
}
@@ -1287,7 +1295,7 @@ func CreateRepository(u *User, opts CreateRepoOptions) (_ *Repository, err error
12871295
return nil, err
12881296
}
12891297

1290-
if err = createRepository(sess, u, repo); err != nil {
1298+
if err = createRepository(sess, doer, u, repo); err != nil {
12911299
return nil, err
12921300
}
12931301

@@ -1623,7 +1631,7 @@ func UpdateRepositoryUnits(repo *Repository, units []RepoUnit) (err error) {
16231631
}
16241632

16251633
// DeleteRepository deletes a repository for a user or organization.
1626-
func DeleteRepository(uid, repoID int64) error {
1634+
func DeleteRepository(doer *User, uid, repoID int64) error {
16271635
// In case is a organization.
16281636
org, err := GetUserByID(uid)
16291637
if err != nil {
@@ -1781,6 +1789,18 @@ func DeleteRepository(uid, repoID int64) error {
17811789
return fmt.Errorf("Commit: %v", err)
17821790
}
17831791

1792+
if org.IsOrganization() {
1793+
if err = PrepareWebhooks(repo, HookEventRepository, &api.RepositoryPayload{
1794+
Action: api.HookRepoDeleted,
1795+
Repository: repo.APIFormat(AccessModeOwner),
1796+
Organization: org.APIFormat(),
1797+
Sender: doer.APIFormat(),
1798+
}); err != nil {
1799+
return err
1800+
}
1801+
go HookQueue.Add(repo.ID)
1802+
}
1803+
17841804
return nil
17851805
}
17861806

@@ -1974,7 +1994,7 @@ func gatherMissingRepoRecords() ([]*Repository, error) {
19741994
}
19751995

19761996
// DeleteMissingRepositories deletes all repository records that lost Git files.
1977-
func DeleteMissingRepositories() error {
1997+
func DeleteMissingRepositories(doer *User) error {
19781998
repos, err := gatherMissingRepoRecords()
19791999
if err != nil {
19802000
return fmt.Errorf("gatherMissingRepoRecords: %v", err)
@@ -1986,7 +2006,7 @@ func DeleteMissingRepositories() error {
19862006

19872007
for _, repo := range repos {
19882008
log.Trace("Deleting %d/%d...", repo.OwnerID, repo.ID)
1989-
if err := DeleteRepository(repo.OwnerID, repo.ID); err != nil {
2009+
if err := DeleteRepository(doer, repo.OwnerID, repo.ID); err != nil {
19902010
if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepository [%d]: %v", repo.ID, err)); err2 != nil {
19912011
return fmt.Errorf("CreateRepositoryNotice: %v", err)
19922012
}
@@ -2226,7 +2246,7 @@ func HasForkedRepo(ownerID, repoID int64) (*Repository, bool) {
22262246
}
22272247

22282248
// ForkRepository forks a repository
2229-
func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) {
2249+
func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *Repository, err error) {
22302250
forkedRepo, err := oldRepo.GetUserFork(u.ID)
22312251
if err != nil {
22322252
return nil, err
@@ -2256,7 +2276,7 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit
22562276
return nil, err
22572277
}
22582278

2259-
if err = createRepository(sess, u, repo); err != nil {
2279+
if err = createRepository(sess, doer, u, repo); err != nil {
22602280
return nil, err
22612281
}
22622282

models/repo_test.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,12 @@ func TestGetUserFork(t *testing.T) {
118118
func TestForkRepository(t *testing.T) {
119119
assert.NoError(t, PrepareTestDatabase())
120120

121-
// User13 has repo 11 forked from repo10
122-
repo, err := GetRepositoryByID(10)
123-
assert.NoError(t, err)
124-
assert.NotNil(t, repo)
121+
// user 13 has already forked repo10
122+
user := AssertExistsAndLoadBean(t, &User{ID: 13}).(*User)
123+
repo := AssertExistsAndLoadBean(t, &Repository{ID: 10}).(*Repository)
125124

126-
repo, err = ForkRepository(&User{ID: 13}, repo, "test", "test")
127-
assert.Nil(t, repo)
125+
fork, err := ForkRepository(user, user, repo, "test", "test")
126+
assert.Nil(t, fork)
128127
assert.Error(t, err)
129128
assert.True(t, IsErrRepoAlreadyExist(err))
130129
}

models/webhook.go

+30-6
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ type HookEvents struct {
6868
Create bool `json:"create"`
6969
Push bool `json:"push"`
7070
PullRequest bool `json:"pull_request"`
71+
Repository bool `json:"repository"`
7172
}
7273

7374
// HookEvent represents events that will delivery hook.
@@ -188,6 +189,12 @@ func (w *Webhook) HasPullRequestEvent() bool {
188189
(w.ChooseEvents && w.HookEvents.PullRequest)
189190
}
190191

192+
// HasRepositoryEvent returns if hook enabled repository event.
193+
func (w *Webhook) HasRepositoryEvent() bool {
194+
return w.SendEverything ||
195+
(w.ChooseEvents && w.HookEvents.Repository)
196+
}
197+
191198
// EventsArray returns an array of hook events
192199
func (w *Webhook) EventsArray() []string {
193200
events := make([]string, 0, 3)
@@ -239,8 +246,12 @@ func GetWebhookByOrgID(orgID, id int64) (*Webhook, error) {
239246

240247
// GetActiveWebhooksByRepoID returns all active webhooks of repository.
241248
func GetActiveWebhooksByRepoID(repoID int64) ([]*Webhook, error) {
249+
return getActiveWebhooksByRepoID(x, repoID)
250+
}
251+
252+
func getActiveWebhooksByRepoID(e Engine, repoID int64) ([]*Webhook, error) {
242253
webhooks := make([]*Webhook, 0, 5)
243-
return webhooks, x.Where("is_active=?", true).
254+
return webhooks, e.Where("is_active=?", true).
244255
Find(&webhooks, &Webhook{RepoID: repoID})
245256
}
246257

@@ -252,7 +263,11 @@ func GetWebhooksByRepoID(repoID int64) ([]*Webhook, error) {
252263

253264
// GetActiveWebhooksByOrgID returns all active webhooks for an organization.
254265
func GetActiveWebhooksByOrgID(orgID int64) (ws []*Webhook, err error) {
255-
err = x.
266+
return getActiveWebhooksByOrgID(x, orgID)
267+
}
268+
269+
func getActiveWebhooksByOrgID(e Engine, orgID int64) (ws []*Webhook, err error) {
270+
err = e.
256271
Where("org_id=?", orgID).
257272
And("is_active=?", true).
258273
Find(&ws)
@@ -366,6 +381,7 @@ const (
366381
HookEventCreate HookEventType = "create"
367382
HookEventPush HookEventType = "push"
368383
HookEventPullRequest HookEventType = "pull_request"
384+
HookEventRepository HookEventType = "repository"
369385
)
370386

371387
// HookRequest represents hook task request information.
@@ -484,6 +500,10 @@ func UpdateHookTask(t *HookTask) error {
484500

485501
// PrepareWebhook adds special webhook to task queue for given payload.
486502
func PrepareWebhook(w *Webhook, repo *Repository, event HookEventType, p api.Payloader) error {
503+
return prepareWebhook(x, w, repo, event, p)
504+
}
505+
506+
func prepareWebhook(e Engine, w *Webhook, repo *Repository, event HookEventType, p api.Payloader) error {
487507
switch event {
488508
case HookEventCreate:
489509
if !w.HasCreateEvent() {
@@ -535,15 +555,19 @@ func PrepareWebhook(w *Webhook, repo *Repository, event HookEventType, p api.Pay
535555

536556
// PrepareWebhooks adds new webhooks to task queue for given payload.
537557
func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) error {
538-
ws, err := GetActiveWebhooksByRepoID(repo.ID)
558+
return prepareWebhooks(x, repo, event, p)
559+
}
560+
561+
func prepareWebhooks(e Engine, repo *Repository, event HookEventType, p api.Payloader) error {
562+
ws, err := getActiveWebhooksByRepoID(e, repo.ID)
539563
if err != nil {
540564
return fmt.Errorf("GetActiveWebhooksByRepoID: %v", err)
541565
}
542566

543567
// check if repo belongs to org and append additional webhooks
544-
if repo.MustOwner().IsOrganization() {
568+
if repo.mustOwner(e).IsOrganization() {
545569
// get hooks for org
546-
orgHooks, err := GetActiveWebhooksByOrgID(repo.OwnerID)
570+
orgHooks, err := getActiveWebhooksByOrgID(e, repo.OwnerID)
547571
if err != nil {
548572
return fmt.Errorf("GetActiveWebhooksByOrgID: %v", err)
549573
}
@@ -555,7 +579,7 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
555579
}
556580

557581
for _, w := range ws {
558-
if err = PrepareWebhook(w, repo, event, p); err != nil {
582+
if err = prepareWebhook(e, w, repo, event, p); err != nil {
559583
return err
560584
}
561585
}

modules/auth/repo_form.go

+1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ type WebhookForm struct {
124124
Create bool
125125
Push bool
126126
PullRequest bool
127+
Repository bool
127128
Active bool
128129
}
129130

options/locale/locale_en-US.ini

+2
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,8 @@ settings.event_pull_request = Pull Request
892892
settings.event_pull_request_desc = Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
893893
settings.event_push = Push
894894
settings.event_push_desc = Git push to a repository
895+
settings.event_repository = Repository
896+
settings.event_repository_desc = Repository created or deleted
895897
settings.active = Active
896898
settings.active_helper = Information about the event which triggered the hook will be sent as well.
897899
settings.add_hook_success = New webhook has been added.

routers/admin/admin.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ func Dashboard(ctx *context.Context) {
145145
err = models.DeleteRepositoryArchives()
146146
case cleanMissingRepos:
147147
success = ctx.Tr("admin.dashboard.delete_missing_repos_success")
148-
err = models.DeleteMissingRepositories()
148+
err = models.DeleteMissingRepositories(ctx.User)
149149
case gitGCRepos:
150150
success = ctx.Tr("admin.dashboard.git_gc_repos_success")
151151
err = models.GitGcRepos()

routers/admin/repos.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func DeleteRepo(ctx *context.Context) {
3939
return
4040
}
4141

42-
if err := models.DeleteRepository(repo.MustOwner().ID, repo.ID); err != nil {
42+
if err := models.DeleteRepository(ctx.User, repo.MustOwner().ID, repo.ID); err != nil {
4343
ctx.Handle(500, "DeleteRepository", err)
4444
return
4545
}

routers/api/v1/repo/fork.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func CreateFork(ctx *context.APIContext, form api.CreateForkOption) {
7373
}
7474
forker = org
7575
}
76-
fork, err := models.ForkRepository(forker, repo, repo.Name, repo.Description)
76+
fork, err := models.ForkRepository(ctx.User, forker, repo, repo.Name, repo.Description)
7777
if err != nil {
7878
ctx.Error(500, "ForkRepository", err)
7979
return

routers/api/v1/repo/repo.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func Search(ctx *context.APIContext) {
105105

106106
// CreateUserRepo create a repository for a user
107107
func CreateUserRepo(ctx *context.APIContext, owner *models.User, opt api.CreateRepoOption) {
108-
repo, err := models.CreateRepository(owner, models.CreateRepoOptions{
108+
repo, err := models.CreateRepository(ctx.User, owner, models.CreateRepoOptions{
109109
Name: opt.Name,
110110
Description: opt.Description,
111111
Gitignores: opt.Gitignores,
@@ -121,7 +121,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *models.User, opt api.CreateR
121121
ctx.Error(422, "", err)
122122
} else {
123123
if repo != nil {
124-
if err = models.DeleteRepository(ctx.User.ID, repo.ID); err != nil {
124+
if err = models.DeleteRepository(ctx.User, ctx.User.ID, repo.ID); err != nil {
125125
log.Error(4, "DeleteRepository: %v", err)
126126
}
127127
}
@@ -254,7 +254,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
254254
return
255255
}
256256

257-
repo, err := models.MigrateRepository(ctxUser, models.MigrateRepoOptions{
257+
repo, err := models.MigrateRepository(ctx.User, ctxUser, models.MigrateRepoOptions{
258258
Name: form.RepoName,
259259
Description: form.Description,
260260
IsPrivate: form.Private || setting.Repository.ForcePrivate,
@@ -263,7 +263,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
263263
})
264264
if err != nil {
265265
if repo != nil {
266-
if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil {
266+
if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil {
267267
log.Error(4, "DeleteRepository: %v", errDelete)
268268
}
269269
}
@@ -345,7 +345,7 @@ func Delete(ctx *context.APIContext) {
345345
return
346346
}
347347

348-
if err := models.DeleteRepository(owner.ID, repo.ID); err != nil {
348+
if err := models.DeleteRepository(ctx.User, owner.ID, repo.ID); err != nil {
349349
ctx.Error(500, "DeleteRepository", err)
350350
return
351351
}

routers/repo/pull.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func ForkPost(ctx *context.Context, form auth.CreateRepoForm) {
125125
}
126126
}
127127

128-
repo, err := models.ForkRepository(ctxUser, forkRepo, form.RepoName, form.Description)
128+
repo, err := models.ForkRepository(ctx.User, ctxUser, forkRepo, form.RepoName, form.Description)
129129
if err != nil {
130130
ctx.Data["Err_RepoName"] = true
131131
switch {

routers/repo/repo.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
127127
return
128128
}
129129

130-
repo, err := models.CreateRepository(ctxUser, models.CreateRepoOptions{
130+
repo, err := models.CreateRepository(ctx.User, ctxUser, models.CreateRepoOptions{
131131
Name: form.RepoName,
132132
Description: form.Description,
133133
Gitignores: form.Gitignores,
@@ -143,7 +143,7 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
143143
}
144144

145145
if repo != nil {
146-
if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil {
146+
if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil {
147147
log.Error(4, "DeleteRepository: %v", errDelete)
148148
}
149149
}
@@ -204,7 +204,7 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
204204
return
205205
}
206206

207-
repo, err := models.MigrateRepository(ctxUser, models.MigrateRepoOptions{
207+
repo, err := models.MigrateRepository(ctx.User, ctxUser, models.MigrateRepoOptions{
208208
Name: form.RepoName,
209209
Description: form.Description,
210210
IsPrivate: form.Private || setting.Repository.ForcePrivate,
@@ -218,7 +218,7 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
218218
}
219219

220220
if repo != nil {
221-
if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil {
221+
if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil {
222222
log.Error(4, "DeleteRepository: %v", errDelete)
223223
}
224224
}

routers/repo/setting.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
314314
}
315315
}
316316

317-
if err := models.DeleteRepository(ctx.Repo.Owner.ID, repo.ID); err != nil {
317+
if err := models.DeleteRepository(ctx.User, ctx.Repo.Owner.ID, repo.ID); err != nil {
318318
ctx.Handle(500, "DeleteRepository", err)
319319
return
320320
}

routers/repo/webhook.go

+1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ func ParseHookEvent(form auth.WebhookForm) *models.HookEvent {
121121
Create: form.Create,
122122
Push: form.Push,
123123
PullRequest: form.PullRequest,
124+
Repository: form.Repository,
124125
},
125126
}
126127
}

0 commit comments

Comments
 (0)