Skip to content

Commit 3636a2f

Browse files
author
Segev Finer
committed
Add API for manipulating Git hooks
Signed-off-by: Segev Finer <[email protected]>
1 parent 22d3d02 commit 3636a2f

File tree

11 files changed

+522
-15
lines changed

11 files changed

+522
-15
lines changed

Gopkg.lock

Lines changed: 8 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ ignored = ["google.golang.org/appengine*"]
77
non-go = true
88

99
[[constraint]]
10-
branch = "master"
10+
branch = "git-hook"
1111
name = "code.gitea.io/git"
12+
source = "https://github.com/codeocean/gitea-git.git"
1213

1314
[[constraint]]
14-
branch = "master"
15+
branch = "git-hook"
1516
name = "code.gitea.io/sdk"
17+
source = "https://github.com/codeocean/gitea-go-sdk.git"
1618

1719
[[constraint]]
1820
revision = "05d86ea8f6e30456949f612cf68cf4a27ce8c9c5"

modules/context/api.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,10 @@ func APIContexter() macaron.Handler {
124124
}
125125

126126
// ReferencesGitRepo injects the GitRepo into the Context
127-
func ReferencesGitRepo() macaron.Handler {
127+
func ReferencesGitRepo(allowEmpty bool) macaron.Handler {
128128
return func(ctx *APIContext) {
129129
// Empty repository does not have reference information.
130-
if ctx.Repo.Repository.IsEmpty {
130+
if !allowEmpty && ctx.Repo.Repository.IsEmpty {
131131
return
132132
}
133133

routers/api/v1/api.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,15 @@ func reqOrgOwnership() macaron.Handler {
301301
}
302302
}
303303

304+
func reqGitHook() macaron.Handler {
305+
return func(ctx *context.APIContext) {
306+
if !ctx.User.CanEditGitHook() {
307+
ctx.NotFound("GitHookService", nil)
308+
return
309+
}
310+
}
311+
}
312+
304313
func orgAssignment(args ...bool) macaron.Handler {
305314
var (
306315
assignOrg bool
@@ -498,6 +507,14 @@ func RegisterRoutes(m *macaron.Macaron) {
498507
Delete(repo.DeleteHook)
499508
m.Post("/tests", context.RepoRef(), repo.TestHook)
500509
})
510+
m.Group("/git", func() {
511+
m.Combo("").Get(repo.ListGitHooks)
512+
m.Group("/:id", func() {
513+
m.Combo("").Get(repo.GetGitHook).
514+
Patch(bind(api.EditGitHookOption{}), repo.EditGitHook).
515+
Delete(repo.DeleteGitHook)
516+
})
517+
}, reqGitHook(), context.ReferencesGitRepo(true))
501518
}, reqToken(), reqAdmin())
502519
m.Group("/collaborators", func() {
503520
m.Get("", repo.ListCollaborators)
@@ -589,10 +606,10 @@ func RegisterRoutes(m *macaron.Macaron) {
589606
})
590607
m.Group("/releases", func() {
591608
m.Combo("").Get(repo.ListReleases).
592-
Post(reqToken(), reqRepoWriter(models.UnitTypeReleases), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease)
609+
Post(reqToken(), reqRepoWriter(models.UnitTypeReleases), context.ReferencesGitRepo(false), bind(api.CreateReleaseOption{}), repo.CreateRelease)
593610
m.Group("/:id", func() {
594611
m.Combo("").Get(repo.GetRelease).
595-
Patch(reqToken(), reqRepoWriter(models.UnitTypeReleases), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease).
612+
Patch(reqToken(), reqRepoWriter(models.UnitTypeReleases), context.ReferencesGitRepo(false), bind(api.EditReleaseOption{}), repo.EditRelease).
596613
Delete(reqToken(), reqRepoWriter(models.UnitTypeReleases), repo.DeleteRelease)
597614
m.Group("/assets", func() {
598615
m.Combo("").Get(repo.ListReleaseAttachments).
@@ -614,7 +631,7 @@ func RegisterRoutes(m *macaron.Macaron) {
614631
m.Combo("/merge").Get(repo.IsPullRequestMerged).
615632
Post(reqToken(), mustNotBeArchived, reqRepoWriter(models.UnitTypePullRequests), bind(auth.MergePullRequestForm{}), repo.MergePullRequest)
616633
})
617-
}, mustAllowPulls, reqRepoReader(models.UnitTypeCode), context.ReferencesGitRepo())
634+
}, mustAllowPulls, reqRepoReader(models.UnitTypeCode), context.ReferencesGitRepo(false))
618635
m.Group("/statuses", func() {
619636
m.Combo("/:sha").Get(repo.GetCommitStatuses).
620637
Post(reqToken(), bind(api.CreateStatusOption{}), repo.NewCommitStatus)

routers/api/v1/convert/convert.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,15 @@ func ToHook(repoLink string, w *models.Webhook) *api.Hook {
180180
}
181181
}
182182

183+
// ToGitHook convert git.Hook to api.GitHook
184+
func ToGitHook(h *git.Hook) *api.GitHook {
185+
return &api.GitHook{
186+
Name: h.Name(),
187+
IsActive: h.IsActive,
188+
Content: h.Content,
189+
}
190+
}
191+
183192
// ToDeployKey convert models.DeployKey to api.DeployKey
184193
func ToDeployKey(apiLink string, key *models.DeployKey) *api.DeployKey {
185194
return &api.DeployKey{

routers/api/v1/repo/git_hook.go

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
// Copyright 2019 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package repo
6+
7+
import (
8+
"code.gitea.io/git"
9+
"code.gitea.io/gitea/modules/context"
10+
"code.gitea.io/gitea/routers/api/v1/convert"
11+
api "code.gitea.io/sdk/gitea"
12+
)
13+
14+
// ListGitHooks list all Git hooks of a repository
15+
func ListGitHooks(ctx *context.APIContext) {
16+
// swagger:operation GET /repos/{owner}/{repo}/hooks/git repository repoListGitHooks
17+
// ---
18+
// summary: List the Git hooks in a repository
19+
// produces:
20+
// - application/json
21+
// parameters:
22+
// - name: owner
23+
// in: path
24+
// description: owner of the repo
25+
// type: string
26+
// required: true
27+
// - name: repo
28+
// in: path
29+
// description: name of the repo
30+
// type: string
31+
// required: true
32+
// responses:
33+
// "200":
34+
// "$ref": "#/responses/GitHookList"
35+
hooks, err := ctx.Repo.GitRepo.Hooks()
36+
if err != nil {
37+
ctx.Error(500, "Hooks", err)
38+
return
39+
}
40+
41+
apiHooks := make([]*api.GitHook, len(hooks))
42+
for i := range hooks {
43+
apiHooks[i] = convert.ToGitHook(hooks[i])
44+
}
45+
ctx.JSON(200, &apiHooks)
46+
}
47+
48+
// GetGitHook get a repo's Git hook by id
49+
func GetGitHook(ctx *context.APIContext) {
50+
// swagger:operation GET /repos/{owner}/{repo}/hooks/git/{id} repository repoGetGitHook
51+
// ---
52+
// summary: Get a Git hook
53+
// produces:
54+
// - application/json
55+
// parameters:
56+
// - name: owner
57+
// in: path
58+
// description: owner of the repo
59+
// type: string
60+
// required: true
61+
// - name: repo
62+
// in: path
63+
// description: name of the repo
64+
// type: string
65+
// required: true
66+
// - name: id
67+
// in: path
68+
// description: id of the hook to get
69+
// type: string
70+
// required: true
71+
// responses:
72+
// "200":
73+
// "$ref": "#/responses/GitHook"
74+
// "404":
75+
// "$ref": "#/responses/notFound"
76+
hookID := ctx.Params(":id")
77+
hook, err := ctx.Repo.GitRepo.GetHook(hookID)
78+
if err != nil {
79+
if err == git.ErrNotValidHook {
80+
ctx.NotFound()
81+
} else {
82+
ctx.Error(500, "GetHook", err)
83+
}
84+
return
85+
}
86+
ctx.JSON(200, convert.ToGitHook(hook))
87+
}
88+
89+
// EditGitHook modify a Git hook of a repository
90+
func EditGitHook(ctx *context.APIContext, form api.EditGitHookOption) {
91+
// swagger:operation PATCH /repos/{owner}/{repo}/hooks/git/{id} repository repoEditGitHook
92+
// ---
93+
// summary: Edit a Git hook in a repository
94+
// produces:
95+
// - application/json
96+
// parameters:
97+
// - name: owner
98+
// in: path
99+
// description: owner of the repo
100+
// type: string
101+
// required: true
102+
// - name: repo
103+
// in: path
104+
// description: name of the repo
105+
// type: string
106+
// required: true
107+
// - name: id
108+
// in: path
109+
// description: id of the hook to get
110+
// type: string
111+
// required: true
112+
// - name: body
113+
// in: body
114+
// schema:
115+
// "$ref": "#/definitions/EditGitHookOption"
116+
// responses:
117+
// "200":
118+
// "$ref": "#/responses/GitHook"
119+
// "404":
120+
// "$ref": "#/responses/notFound"
121+
hookID := ctx.Params(":id")
122+
hook, err := ctx.Repo.GitRepo.GetHook(hookID)
123+
if err != nil {
124+
if err == git.ErrNotValidHook {
125+
ctx.NotFound()
126+
} else {
127+
ctx.Error(500, "GetHook", err)
128+
}
129+
return
130+
}
131+
132+
hook.Content = form.Content
133+
if err = hook.Update(); err != nil {
134+
ctx.Error(500, "hook.Update", err)
135+
return
136+
}
137+
138+
ctx.JSON(200, convert.ToGitHook(hook))
139+
}
140+
141+
// DeleteGitHook delete a Git hook of a repository
142+
func DeleteGitHook(ctx *context.APIContext) {
143+
// swagger:operation DELETE /repos/{owner}/{repo}/hooks/git/{id} repository repoDeleteGitHook
144+
// ---
145+
// summary: Delete a Git hook in a repository
146+
// produces:
147+
// - application/json
148+
// parameters:
149+
// - name: owner
150+
// in: path
151+
// description: owner of the repo
152+
// type: string
153+
// required: true
154+
// - name: repo
155+
// in: path
156+
// description: name of the repo
157+
// type: string
158+
// required: true
159+
// - name: id
160+
// in: path
161+
// description: id of the hook to get
162+
// type: string
163+
// required: true
164+
// responses:
165+
// "204":
166+
// "$ref": "#/responses/empty"
167+
// "404":
168+
// "$ref": "#/responses/notFound"
169+
hookID := ctx.Params(":id")
170+
hook, err := ctx.Repo.GitRepo.GetHook(hookID)
171+
if err != nil {
172+
if err == git.ErrNotValidHook {
173+
ctx.NotFound()
174+
} else {
175+
ctx.Error(500, "GetHook", err)
176+
}
177+
return
178+
}
179+
180+
hook.Content = ""
181+
if err = hook.Update(); err != nil {
182+
ctx.Error(500, "hook.Update", err)
183+
return
184+
}
185+
186+
ctx.Status(204)
187+
}

routers/api/v1/swagger/options.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ type swaggerParameterBodies struct {
2828
// in:body
2929
EditHookOption api.EditHookOption
3030

31+
// in:body
32+
EditGitHookOption api.EditGitHookOption
33+
3134
// in:body
3235
CreateIssueOption api.CreateIssueOption
3336
// in:body

routers/api/v1/swagger/repo.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,20 @@ type swaggerResponseHookList struct {
7171
Body []api.Branch `json:"body"`
7272
}
7373

74+
// GitHook
75+
// swagger:response GitHook
76+
type swaggerResponseGitHook struct {
77+
// in:body
78+
Body api.GitHook `json:"body"`
79+
}
80+
81+
// GitHookList
82+
// swagger:response GitHookList
83+
type swaggerResponseGitHookList struct {
84+
// in:body
85+
Body []api.GitHook `json:"body"`
86+
}
87+
7488
// Release
7589
// swagger:response Release
7690
type swaggerResponseRelease struct {

0 commit comments

Comments
 (0)