diff --git a/models/fixtures/hook_task.yml b/models/fixtures/hook_task.yml index 151fe250f28..bb662345cdf 100644 --- a/models/fixtures/hook_task.yml +++ b/models/fixtures/hook_task.yml @@ -3,3 +3,4 @@ repo_id: 1 hook_id: 1 uuid: uuid1 + is_delivered: true diff --git a/modules/test/context_tests.go b/modules/test/context_tests.go index bd5ea3fd38b..b2b96fff9d4 100644 --- a/modules/test/context_tests.go +++ b/modules/test/context_tests.go @@ -13,10 +13,11 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" + "net/http/httptest" + "github.com/go-macaron/session" "github.com/stretchr/testify/assert" "gopkg.in/macaron.v1" - "net/http/httptest" ) // MockContext mock context for unit tests @@ -48,6 +49,16 @@ func LoadRepo(t *testing.T, ctx *context.Context, repoID int64) { ctx.Repo.RepoLink = ctx.Repo.Repository.Link() } +// LoadRepoCommit loads a repo's commit into a test context. +func LoadRepoCommit(t *testing.T, ctx *context.Context) { + gitRepo, err := git.OpenRepository(ctx.Repo.Repository.RepoPath()) + assert.NoError(t, err) + branch, err := gitRepo.GetHEADBranch() + assert.NoError(t, err) + ctx.Repo.Commit, err = gitRepo.GetBranchCommit(branch.Name) + assert.NoError(t, err) +} + // LoadUser load a user into a test context. func LoadUser(t *testing.T, ctx *context.Context, userID int64) { ctx.User = models.AssertExistsAndLoadBean(t, &models.User{ID: userID}).(*models.User) diff --git a/public/swagger.v1.json b/public/swagger.v1.json index dec618988b6..86bf20a9a88 100644 --- a/public/swagger.v1.json +++ b/public/swagger.v1.json @@ -1565,6 +1565,46 @@ } } }, + "/repos/{owner}/{repo}/hooks/{id}/tests": { + "post": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Test a push webhook", + "operationId": "repoTestHook", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "id of the hook to test", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "$ref": "#/responses/empty" + } + } + } + }, "/repos/{owner}/{repo}/issue/{index}/comments": { "get": { "produces": [ diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 02606bdfd06..eec55cac673 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -382,9 +382,12 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/hooks", func() { m.Combo("").Get(repo.ListHooks). Post(bind(api.CreateHookOption{}), repo.CreateHook) - m.Combo("/:id").Get(repo.GetHook). - Patch(bind(api.EditHookOption{}), repo.EditHook). - Delete(repo.DeleteHook) + m.Group("/:id", func() { + m.Combo("").Get(repo.GetHook). + Patch(bind(api.EditHookOption{}), repo.EditHook). + Delete(repo.DeleteHook) + m.Post("/tests", context.RepoRef(), repo.TestHook) + }) }, reqToken(), reqRepoWriter()) m.Group("/collaborators", func() { m.Get("", repo.ListCollaborators) diff --git a/routers/api/v1/repo/hook.go b/routers/api/v1/repo/hook.go index 9c39094bae3..e412a7f1f2d 100644 --- a/routers/api/v1/repo/hook.go +++ b/routers/api/v1/repo/hook.go @@ -5,11 +5,11 @@ package repo import ( + "code.gitea.io/git" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/routers/api/v1/convert" "code.gitea.io/gitea/routers/api/v1/utils" - api "code.gitea.io/sdk/gitea" ) @@ -82,6 +82,62 @@ func GetHook(ctx *context.APIContext) { ctx.JSON(200, convert.ToHook(repo.RepoLink, hook)) } +// TestHook tests a hook +func TestHook(ctx *context.APIContext) { + // swagger:operation POST /repos/{owner}/{repo}/hooks/{id}/tests repository repoTestHook + // --- + // summary: Test a push webhook + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: id + // in: path + // description: id of the hook to test + // type: integer + // required: true + // responses: + // "204": + // "$ref": "#/responses/empty" + if ctx.Repo.Commit == nil { + // if repo does not have any commits, then don't send a webhook + ctx.Status(204) + return + } + + hookID := ctx.ParamsInt64(":id") + hook, err := utils.GetRepoHook(ctx, ctx.Repo.Repository.ID, hookID) + if err != nil { + return + } + + if err := models.PrepareWebhook(hook, ctx.Repo.Repository, models.HookEventPush, &api.PushPayload{ + Ref: git.BranchPrefix + ctx.Repo.Repository.DefaultBranch, + Before: ctx.Repo.Commit.ID.String(), + After: ctx.Repo.Commit.ID.String(), + Commits: []*api.PayloadCommit{ + convert.ToCommit(ctx.Repo.Repository, ctx.Repo.Commit), + }, + Repo: ctx.Repo.Repository.APIFormat(models.AccessModeNone), + Pusher: ctx.User.APIFormat(), + Sender: ctx.User.APIFormat(), + }); err != nil { + ctx.Error(500, "PrepareWebhook: ", err) + return + } + go models.HookQueue.Add(ctx.Repo.Repository.ID) + ctx.Status(204) +} + // CreateHook create a hook for a repository func CreateHook(ctx *context.APIContext, form api.CreateHookOption) { // swagger:operation POST /repos/{owner}/{repo}/hooks repository repoCreateHook diff --git a/routers/api/v1/repo/hook_test.go b/routers/api/v1/repo/hook_test.go new file mode 100644 index 00000000000..8ed4bc4b0c3 --- /dev/null +++ b/routers/api/v1/repo/hook_test.go @@ -0,0 +1,33 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repo + +import ( + "net/http" + "testing" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/test" + + "github.com/stretchr/testify/assert" +) + +func TestTestHook(t *testing.T) { + models.PrepareTestEnv(t) + + ctx := test.MockContext(t, "user2/repo1/wiki/_pages") + ctx.SetParams(":id", "1") + test.LoadRepo(t, ctx, 1) + test.LoadRepoCommit(t, ctx) + test.LoadUser(t, ctx, 2) + TestHook(&context.APIContext{Context: ctx, Org: nil}) + assert.EqualValues(t, http.StatusNoContent, ctx.Resp.Status()) + + models.AssertExistsAndLoadBean(t, &models.HookTask{ + RepoID: 1, + HookID: 1, + }, models.Cond("is_delivered=?", false)) +} diff --git a/routers/api/v1/repo/main_test.go b/routers/api/v1/repo/main_test.go new file mode 100644 index 00000000000..656758ffba4 --- /dev/null +++ b/routers/api/v1/repo/main_test.go @@ -0,0 +1,16 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repo + +import ( + "path/filepath" + "testing" + + "code.gitea.io/gitea/models" +) + +func TestMain(m *testing.M) { + models.MainTest(m, filepath.Join("..", "..", "..", "..")) +}