Skip to content

Commit b91057b

Browse files
appleboyGiteaBot
andauthored
feat(API): add route and implementation for creating/updating repository secret (#26766)
spec: https://docs.github.com/en/rest/actions/secrets?apiVersion=2022-11-28#create-or-update-a-repository-secret - Add a new route for creating or updating a secret value in a repository - Create a new file `routers/api/v1/repo/action.go` with the implementation of the `CreateOrUpdateSecret` function - Update the Swagger documentation for the `updateRepoSecret` operation in the `v1_json.tmpl` template file --------- Signed-off-by: Bo-Yi Wu <[email protected]> Co-authored-by: Giteabot <[email protected]>
1 parent 2d9249b commit b91057b

File tree

5 files changed

+174
-17
lines changed

5 files changed

+174
-17
lines changed

models/secret/secret.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,31 @@ func DeleteSecret(ctx context.Context, orgID, repoID int64, name string) error {
160160

161161
return nil
162162
}
163+
164+
// CreateOrUpdateSecret creates or updates a secret and returns true if it was created
165+
func CreateOrUpdateSecret(ctx context.Context, orgID, repoID int64, name, data string) (bool, error) {
166+
sc := new(Secret)
167+
name = strings.ToUpper(name)
168+
has, err := db.GetEngine(ctx).
169+
Where("owner_id=?", orgID).
170+
And("repo_id=?", repoID).
171+
And("name=?", name).
172+
Get(sc)
173+
if err != nil {
174+
return false, err
175+
}
176+
177+
if !has {
178+
_, err = InsertEncryptedSecret(ctx, orgID, repoID, name, data)
179+
if err != nil {
180+
return false, err
181+
}
182+
return true, nil
183+
}
184+
185+
if err := UpdateSecret(ctx, orgID, repoID, name, data); err != nil {
186+
return false, err
187+
}
188+
189+
return false, nil
190+
}

routers/api/v1/api.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,10 @@ func Routes() *web.Route {
933933
m.Post("/accept", repo.AcceptTransfer)
934934
m.Post("/reject", repo.RejectTransfer)
935935
}, reqToken())
936+
m.Group("/actions/secrets", func() {
937+
m.Combo("/{secretname}").
938+
Put(reqToken(), reqOwner(), bind(api.CreateOrUpdateSecretOption{}), repo.CreateOrUpdateSecret)
939+
})
936940
m.Group("/hooks/git", func() {
937941
m.Combo("").Get(repo.ListGitHooks)
938942
m.Group("/{id}", func() {
@@ -1301,7 +1305,7 @@ func Routes() *web.Route {
13011305
m.Group("/actions/secrets", func() {
13021306
m.Get("", reqToken(), reqOrgOwnership(), org.ListActionsSecrets)
13031307
m.Combo("/{secretname}").
1304-
Put(reqToken(), reqOrgOwnership(), bind(api.CreateOrUpdateSecretOption{}), org.CreateOrUpdateOrgSecret).
1308+
Put(reqToken(), reqOrgOwnership(), bind(api.CreateOrUpdateSecretOption{}), org.CreateOrUpdateSecret).
13051309
Delete(reqToken(), reqOrgOwnership(), org.DeleteOrgSecret)
13061310
})
13071311
m.Group("/public_members", func() {

routers/api/v1/org/action.go

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func listActionsSecrets(ctx *context.APIContext) {
7474
}
7575

7676
// create or update one secret of the organization
77-
func CreateOrUpdateOrgSecret(ctx *context.APIContext) {
77+
func CreateOrUpdateSecret(ctx *context.APIContext) {
7878
// swagger:operation PUT /orgs/{org}/actions/secrets/{secretname} organization updateOrgSecret
7979
// ---
8080
// summary: Create or Update a secret value in an organization
@@ -108,26 +108,17 @@ func CreateOrUpdateOrgSecret(ctx *context.APIContext) {
108108
// "$ref": "#/responses/forbidden"
109109
secretName := ctx.Params(":secretname")
110110
if err := actions.NameRegexMatch(secretName); err != nil {
111-
ctx.Error(http.StatusBadRequest, "CreateOrUpdateOrgSecret", err)
111+
ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err)
112112
return
113113
}
114114
opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
115-
err := secret_model.UpdateSecret(
116-
ctx, ctx.Org.Organization.ID, 0, secretName, opt.Data,
117-
)
118-
if secret_model.IsErrSecretNotFound(err) {
119-
_, err := secret_model.InsertEncryptedSecret(
120-
ctx, ctx.Org.Organization.ID, 0, secretName, actions.ReserveLineBreakForTextarea(opt.Data),
121-
)
122-
if err != nil {
123-
ctx.Error(http.StatusInternalServerError, "InsertEncryptedSecret", err)
124-
return
125-
}
126-
ctx.Status(http.StatusCreated)
115+
isCreated, err := secret_model.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, secretName, opt.Data)
116+
if err != nil {
117+
ctx.Error(http.StatusInternalServerError, "CreateOrUpdateSecret", err)
127118
return
128119
}
129-
if err != nil {
130-
ctx.Error(http.StatusInternalServerError, "UpdateSecret", err)
120+
if isCreated {
121+
ctx.Status(http.StatusCreated)
131122
return
132123
}
133124

routers/api/v1/repo/action.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package repo
5+
6+
import (
7+
"net/http"
8+
9+
secret_model "code.gitea.io/gitea/models/secret"
10+
"code.gitea.io/gitea/modules/context"
11+
api "code.gitea.io/gitea/modules/structs"
12+
"code.gitea.io/gitea/modules/web"
13+
"code.gitea.io/gitea/routers/web/shared/actions"
14+
)
15+
16+
// create or update one secret of the repository
17+
func CreateOrUpdateSecret(ctx *context.APIContext) {
18+
// swagger:operation PUT /repos/{owner}/{repo}/actions/secrets/{secretname} repository updateRepoSecret
19+
// ---
20+
// summary: Create or Update a secret value in a repository
21+
// consumes:
22+
// - application/json
23+
// produces:
24+
// - application/json
25+
// parameters:
26+
// - name: owner
27+
// in: path
28+
// description: owner of the repository
29+
// type: string
30+
// required: true
31+
// - name: repo
32+
// in: path
33+
// description: name of the repository
34+
// type: string
35+
// required: true
36+
// - name: secretname
37+
// in: path
38+
// description: name of the secret
39+
// type: string
40+
// required: true
41+
// - name: body
42+
// in: body
43+
// schema:
44+
// "$ref": "#/definitions/CreateOrUpdateSecretOption"
45+
// responses:
46+
// "201":
47+
// description: response when creating a secret
48+
// "204":
49+
// description: response when updating a secret
50+
// "400":
51+
// "$ref": "#/responses/error"
52+
// "403":
53+
// "$ref": "#/responses/forbidden"
54+
55+
owner := ctx.Repo.Owner
56+
repo := ctx.Repo.Repository
57+
58+
secretName := ctx.Params(":secretname")
59+
if err := actions.NameRegexMatch(secretName); err != nil {
60+
ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err)
61+
return
62+
}
63+
opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
64+
isCreated, err := secret_model.CreateOrUpdateSecret(ctx, owner.ID, repo.ID, secretName, opt.Data)
65+
if err != nil {
66+
ctx.Error(http.StatusInternalServerError, "CreateOrUpdateSecret", err)
67+
return
68+
}
69+
if isCreated {
70+
ctx.Status(http.StatusCreated)
71+
return
72+
}
73+
74+
ctx.Status(http.StatusNoContent)
75+
}

templates/swagger/v1_json.tmpl

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

0 commit comments

Comments
 (0)