Skip to content

Commit

Permalink
Add API for manipulating Git hooks
Browse files Browse the repository at this point in the history
Signed-off-by: Segev Finer <segev@codeocean.com>
  • Loading branch information
Segev Finer committed Mar 26, 2019
1 parent 22d3d02 commit 3636a2f
Show file tree
Hide file tree
Showing 11 changed files with 522 additions and 15 deletions.
14 changes: 8 additions & 6 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ ignored = ["google.golang.org/appengine*"]
non-go = true

[[constraint]]
branch = "master"
branch = "git-hook"
name = "code.gitea.io/git"
source = "https://github.com/codeocean/gitea-git.git"

[[constraint]]
branch = "master"
branch = "git-hook"
name = "code.gitea.io/sdk"
source = "https://github.com/codeocean/gitea-go-sdk.git"

[[constraint]]
revision = "05d86ea8f6e30456949f612cf68cf4a27ce8c9c5"
Expand Down
4 changes: 2 additions & 2 deletions modules/context/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,10 @@ func APIContexter() macaron.Handler {
}

// ReferencesGitRepo injects the GitRepo into the Context
func ReferencesGitRepo() macaron.Handler {
func ReferencesGitRepo(allowEmpty bool) macaron.Handler {
return func(ctx *APIContext) {
// Empty repository does not have reference information.
if ctx.Repo.Repository.IsEmpty {
if !allowEmpty && ctx.Repo.Repository.IsEmpty {
return
}

Expand Down
23 changes: 20 additions & 3 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,15 @@ func reqOrgOwnership() macaron.Handler {
}
}

func reqGitHook() macaron.Handler {
return func(ctx *context.APIContext) {
if !ctx.User.CanEditGitHook() {
ctx.NotFound("GitHookService", nil)
return
}
}
}

func orgAssignment(args ...bool) macaron.Handler {
var (
assignOrg bool
Expand Down Expand Up @@ -498,6 +507,14 @@ func RegisterRoutes(m *macaron.Macaron) {
Delete(repo.DeleteHook)
m.Post("/tests", context.RepoRef(), repo.TestHook)
})
m.Group("/git", func() {
m.Combo("").Get(repo.ListGitHooks)
m.Group("/:id", func() {
m.Combo("").Get(repo.GetGitHook).
Patch(bind(api.EditGitHookOption{}), repo.EditGitHook).
Delete(repo.DeleteGitHook)
})
}, reqGitHook(), context.ReferencesGitRepo(true))
}, reqToken(), reqAdmin())
m.Group("/collaborators", func() {
m.Get("", repo.ListCollaborators)
Expand Down Expand Up @@ -589,10 +606,10 @@ func RegisterRoutes(m *macaron.Macaron) {
})
m.Group("/releases", func() {
m.Combo("").Get(repo.ListReleases).
Post(reqToken(), reqRepoWriter(models.UnitTypeReleases), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease)
Post(reqToken(), reqRepoWriter(models.UnitTypeReleases), context.ReferencesGitRepo(false), bind(api.CreateReleaseOption{}), repo.CreateRelease)
m.Group("/:id", func() {
m.Combo("").Get(repo.GetRelease).
Patch(reqToken(), reqRepoWriter(models.UnitTypeReleases), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease).
Patch(reqToken(), reqRepoWriter(models.UnitTypeReleases), context.ReferencesGitRepo(false), bind(api.EditReleaseOption{}), repo.EditRelease).
Delete(reqToken(), reqRepoWriter(models.UnitTypeReleases), repo.DeleteRelease)
m.Group("/assets", func() {
m.Combo("").Get(repo.ListReleaseAttachments).
Expand All @@ -614,7 +631,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Combo("/merge").Get(repo.IsPullRequestMerged).
Post(reqToken(), mustNotBeArchived, reqRepoWriter(models.UnitTypePullRequests), bind(auth.MergePullRequestForm{}), repo.MergePullRequest)
})
}, mustAllowPulls, reqRepoReader(models.UnitTypeCode), context.ReferencesGitRepo())
}, mustAllowPulls, reqRepoReader(models.UnitTypeCode), context.ReferencesGitRepo(false))
m.Group("/statuses", func() {
m.Combo("/:sha").Get(repo.GetCommitStatuses).
Post(reqToken(), bind(api.CreateStatusOption{}), repo.NewCommitStatus)
Expand Down
9 changes: 9 additions & 0 deletions routers/api/v1/convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,15 @@ func ToHook(repoLink string, w *models.Webhook) *api.Hook {
}
}

// ToGitHook convert git.Hook to api.GitHook
func ToGitHook(h *git.Hook) *api.GitHook {
return &api.GitHook{
Name: h.Name(),
IsActive: h.IsActive,
Content: h.Content,
}
}

// ToDeployKey convert models.DeployKey to api.DeployKey
func ToDeployKey(apiLink string, key *models.DeployKey) *api.DeployKey {
return &api.DeployKey{
Expand Down
187 changes: 187 additions & 0 deletions routers/api/v1/repo/git_hook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// Copyright 2019 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 (
"code.gitea.io/git"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/routers/api/v1/convert"
api "code.gitea.io/sdk/gitea"
)

// ListGitHooks list all Git hooks of a repository
func ListGitHooks(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/hooks/git repository repoListGitHooks
// ---
// summary: List the Git hooks in a repository
// 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
// responses:
// "200":
// "$ref": "#/responses/GitHookList"
hooks, err := ctx.Repo.GitRepo.Hooks()
if err != nil {
ctx.Error(500, "Hooks", err)
return
}

apiHooks := make([]*api.GitHook, len(hooks))
for i := range hooks {
apiHooks[i] = convert.ToGitHook(hooks[i])
}
ctx.JSON(200, &apiHooks)
}

// GetGitHook get a repo's Git hook by id
func GetGitHook(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/hooks/git/{id} repository repoGetGitHook
// ---
// summary: Get a Git hook
// 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 get
// type: string
// required: true
// responses:
// "200":
// "$ref": "#/responses/GitHook"
// "404":
// "$ref": "#/responses/notFound"
hookID := ctx.Params(":id")
hook, err := ctx.Repo.GitRepo.GetHook(hookID)
if err != nil {
if err == git.ErrNotValidHook {
ctx.NotFound()
} else {
ctx.Error(500, "GetHook", err)
}
return
}
ctx.JSON(200, convert.ToGitHook(hook))
}

// EditGitHook modify a Git hook of a repository
func EditGitHook(ctx *context.APIContext, form api.EditGitHookOption) {
// swagger:operation PATCH /repos/{owner}/{repo}/hooks/git/{id} repository repoEditGitHook
// ---
// summary: Edit a Git hook in a repository
// 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 get
// type: string
// required: true
// - name: body
// in: body
// schema:
// "$ref": "#/definitions/EditGitHookOption"
// responses:
// "200":
// "$ref": "#/responses/GitHook"
// "404":
// "$ref": "#/responses/notFound"
hookID := ctx.Params(":id")
hook, err := ctx.Repo.GitRepo.GetHook(hookID)
if err != nil {
if err == git.ErrNotValidHook {
ctx.NotFound()
} else {
ctx.Error(500, "GetHook", err)
}
return
}

hook.Content = form.Content
if err = hook.Update(); err != nil {
ctx.Error(500, "hook.Update", err)
return
}

ctx.JSON(200, convert.ToGitHook(hook))
}

// DeleteGitHook delete a Git hook of a repository
func DeleteGitHook(ctx *context.APIContext) {
// swagger:operation DELETE /repos/{owner}/{repo}/hooks/git/{id} repository repoDeleteGitHook
// ---
// summary: Delete a Git hook in a repository
// 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 get
// type: string
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/notFound"
hookID := ctx.Params(":id")
hook, err := ctx.Repo.GitRepo.GetHook(hookID)
if err != nil {
if err == git.ErrNotValidHook {
ctx.NotFound()
} else {
ctx.Error(500, "GetHook", err)
}
return
}

hook.Content = ""
if err = hook.Update(); err != nil {
ctx.Error(500, "hook.Update", err)
return
}

ctx.Status(204)
}
3 changes: 3 additions & 0 deletions routers/api/v1/swagger/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ type swaggerParameterBodies struct {
// in:body
EditHookOption api.EditHookOption

// in:body
EditGitHookOption api.EditGitHookOption

// in:body
CreateIssueOption api.CreateIssueOption
// in:body
Expand Down
14 changes: 14 additions & 0 deletions routers/api/v1/swagger/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ type swaggerResponseHookList struct {
Body []api.Branch `json:"body"`
}

// GitHook
// swagger:response GitHook
type swaggerResponseGitHook struct {
// in:body
Body api.GitHook `json:"body"`
}

// GitHookList
// swagger:response GitHookList
type swaggerResponseGitHookList struct {
// in:body
Body []api.GitHook `json:"body"`
}

// Release
// swagger:response Release
type swaggerResponseRelease struct {
Expand Down
Loading

0 comments on commit 3636a2f

Please sign in to comment.