aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBo-Yi Wu <appleboy.tw@gmail.com>2024-04-26 21:11:49 +0800
committerGitHub <noreply@github.com>2024-04-26 21:11:49 +0800
commit852547d0dc70299589c7bf8d00ea462ed709b8e5 (patch)
tree235003f72556874c6115ed21baca6ebecd74dacb
parent993736d838c36e26951b6cfea9c6a549958addd1 (diff)
downloadgitea-852547d0dc70299589c7bf8d00ea462ed709b8e5.tar.gz
gitea-852547d0dc70299589c7bf8d00ea462ed709b8e5.zip
feat(api): enhance Actions Secrets Management API for repository (#30656)
- Add endpoint to list repository action secrets in API routes - Implement `ListActionsSecrets` function to retrieve action secrets from the database - Update Swagger documentation to include the new `/repos/{owner}/{repo}/actions/secrets` endpoint - Add `actions` package import and define new routes for actions, secrets, variables, and runners in `api.go`. - Refactor action-related API functions into `Action` struct methods in `org/action.go` and `repo/action.go`. - Remove `actionAPI` struct and related functions, replacing them with `NewAction()` calls. - Rename `variables.go` to `action.go` in `org` directory. - Delete `runners.go` and `secrets.go` in both `org` and `repo` directories, consolidating their content into `action.go`. - Update copyright year and add new imports in `org/action.go`. - Implement `API` interface in `services/actions/interface.go` for action-related methods. - Remove individual action-related functions and replace them with methods on the `Action` struct in `repo/action.go`. --------- Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> Signed-off-by: appleboy <appleboy.tw@gmail.com>
-rw-r--r--routers/api/v1/api.go80
-rw-r--r--routers/api/v1/org/action.go (renamed from routers/api/v1/org/variables.go)192
-rw-r--r--routers/api/v1/org/runners.go31
-rw-r--r--routers/api/v1/org/secrets.go166
-rw-r--r--routers/api/v1/repo/action.go108
-rw-r--r--routers/api/v1/repo/runners.go34
-rw-r--r--services/actions/interface.go28
-rw-r--r--templates/swagger/v1_json.tmpl48
-rw-r--r--tests/integration/api_repo_secrets_test.go8
9 files changed, 410 insertions, 285 deletions
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 5358906f27..73071aa8df 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -93,6 +93,7 @@ import (
"code.gitea.io/gitea/routers/api/v1/settings"
"code.gitea.io/gitea/routers/api/v1/user"
"code.gitea.io/gitea/routers/common"
+ "code.gitea.io/gitea/services/actions"
"code.gitea.io/gitea/services/auth"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
@@ -835,6 +836,34 @@ func Routes() *web.Route {
SignInRequired: setting.Service.RequireSignInView,
}))
+ addActionsRoutes := func(
+ m *web.Route,
+ reqChecker func(ctx *context.APIContext),
+ act actions.API,
+ ) {
+ m.Group("/actions", func() {
+ m.Group("/secrets", func() {
+ m.Get("", reqToken(), reqChecker, act.ListActionsSecrets)
+ m.Combo("/{secretname}").
+ Put(reqToken(), reqChecker, bind(api.CreateOrUpdateSecretOption{}), act.CreateOrUpdateSecret).
+ Delete(reqToken(), reqChecker, act.DeleteSecret)
+ })
+
+ m.Group("/variables", func() {
+ m.Get("", reqToken(), reqChecker, act.ListVariables)
+ m.Combo("/{variablename}").
+ Get(reqToken(), reqChecker, act.GetVariable).
+ Delete(reqToken(), reqChecker, act.DeleteVariable).
+ Post(reqToken(), reqChecker, bind(api.CreateVariableOption{}), act.CreateVariable).
+ Put(reqToken(), reqChecker, bind(api.UpdateVariableOption{}), act.UpdateVariable)
+ })
+
+ m.Group("/runners", func() {
+ m.Get("/registration-token", reqToken(), reqChecker, act.GetRegistrationToken)
+ })
+ })
+ }
+
m.Group("", func() {
// Miscellaneous (no scope required)
if setting.API.EnableSwagger {
@@ -1073,26 +1102,11 @@ func Routes() *web.Route {
m.Post("/accept", repo.AcceptTransfer)
m.Post("/reject", repo.RejectTransfer)
}, reqToken())
- m.Group("/actions", func() {
- m.Group("/secrets", func() {
- m.Combo("/{secretname}").
- Put(reqToken(), reqOwner(), bind(api.CreateOrUpdateSecretOption{}), repo.CreateOrUpdateSecret).
- Delete(reqToken(), reqOwner(), repo.DeleteSecret)
- })
-
- m.Group("/variables", func() {
- m.Get("", reqToken(), reqOwner(), repo.ListVariables)
- m.Combo("/{variablename}").
- Get(reqToken(), reqOwner(), repo.GetVariable).
- Delete(reqToken(), reqOwner(), repo.DeleteVariable).
- Post(reqToken(), reqOwner(), bind(api.CreateVariableOption{}), repo.CreateVariable).
- Put(reqToken(), reqOwner(), bind(api.UpdateVariableOption{}), repo.UpdateVariable)
- })
-
- m.Group("/runners", func() {
- m.Get("/registration-token", reqToken(), reqOwner(), repo.GetRegistrationToken)
- })
- })
+ addActionsRoutes(
+ m,
+ reqOwner(),
+ repo.NewAction(),
+ )
m.Group("/hooks/git", func() {
m.Combo("").Get(repo.ListGitHooks)
m.Group("/{id}", func() {
@@ -1460,27 +1474,11 @@ func Routes() *web.Route {
m.Combo("/{username}").Get(reqToken(), org.IsMember).
Delete(reqToken(), reqOrgOwnership(), org.DeleteMember)
})
- m.Group("/actions", func() {
- m.Group("/secrets", func() {
- m.Get("", reqToken(), reqOrgOwnership(), org.ListActionsSecrets)
- m.Combo("/{secretname}").
- Put(reqToken(), reqOrgOwnership(), bind(api.CreateOrUpdateSecretOption{}), org.CreateOrUpdateSecret).
- Delete(reqToken(), reqOrgOwnership(), org.DeleteSecret)
- })
-
- m.Group("/variables", func() {
- m.Get("", reqToken(), reqOrgOwnership(), org.ListVariables)
- m.Combo("/{variablename}").
- Get(reqToken(), reqOrgOwnership(), org.GetVariable).
- Delete(reqToken(), reqOrgOwnership(), org.DeleteVariable).
- Post(reqToken(), reqOrgOwnership(), bind(api.CreateVariableOption{}), org.CreateVariable).
- Put(reqToken(), reqOrgOwnership(), bind(api.UpdateVariableOption{}), org.UpdateVariable)
- })
-
- m.Group("/runners", func() {
- m.Get("/registration-token", reqToken(), reqOrgOwnership(), org.GetRegistrationToken)
- })
- })
+ addActionsRoutes(
+ m,
+ reqOrgOwnership(),
+ org.NewAction(),
+ )
m.Group("/public_members", func() {
m.Get("", org.ListPublicMembers)
m.Combo("/{username}").Get(org.IsPublicMember).
diff --git a/routers/api/v1/org/variables.go b/routers/api/v1/org/action.go
index eaf7bdc45b..03a1fa8ccc 100644
--- a/routers/api/v1/org/variables.go
+++ b/routers/api/v1/org/action.go
@@ -9,16 +9,188 @@ import (
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
+ secret_model "code.gitea.io/gitea/models/secret"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
+ "code.gitea.io/gitea/routers/api/v1/shared"
"code.gitea.io/gitea/routers/api/v1/utils"
actions_service "code.gitea.io/gitea/services/actions"
"code.gitea.io/gitea/services/context"
+ secret_service "code.gitea.io/gitea/services/secrets"
)
+// ListActionsSecrets list an organization's actions secrets
+func (Action) ListActionsSecrets(ctx *context.APIContext) {
+ // swagger:operation GET /orgs/{org}/actions/secrets organization orgListActionsSecrets
+ // ---
+ // summary: List an organization's actions secrets
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: org
+ // in: path
+ // description: name of the organization
+ // type: string
+ // required: true
+ // - name: page
+ // in: query
+ // description: page number of results to return (1-based)
+ // type: integer
+ // - name: limit
+ // in: query
+ // description: page size of results
+ // type: integer
+ // responses:
+ // "200":
+ // "$ref": "#/responses/SecretList"
+ // "404":
+ // "$ref": "#/responses/notFound"
+
+ opts := &secret_model.FindSecretsOptions{
+ OwnerID: ctx.Org.Organization.ID,
+ ListOptions: utils.GetListOptions(ctx),
+ }
+
+ secrets, count, err := db.FindAndCount[secret_model.Secret](ctx, opts)
+ if err != nil {
+ ctx.InternalServerError(err)
+ return
+ }
+
+ apiSecrets := make([]*api.Secret, len(secrets))
+ for k, v := range secrets {
+ apiSecrets[k] = &api.Secret{
+ Name: v.Name,
+ Created: v.CreatedUnix.AsTime(),
+ }
+ }
+
+ ctx.SetTotalCountHeader(count)
+ ctx.JSON(http.StatusOK, apiSecrets)
+}
+
+// create or update one secret of the organization
+func (Action) CreateOrUpdateSecret(ctx *context.APIContext) {
+ // swagger:operation PUT /orgs/{org}/actions/secrets/{secretname} organization updateOrgSecret
+ // ---
+ // summary: Create or Update a secret value in an organization
+ // consumes:
+ // - application/json
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: org
+ // in: path
+ // description: name of organization
+ // type: string
+ // required: true
+ // - name: secretname
+ // in: path
+ // description: name of the secret
+ // type: string
+ // required: true
+ // - name: body
+ // in: body
+ // schema:
+ // "$ref": "#/definitions/CreateOrUpdateSecretOption"
+ // responses:
+ // "201":
+ // description: response when creating a secret
+ // "204":
+ // description: response when updating a secret
+ // "400":
+ // "$ref": "#/responses/error"
+ // "404":
+ // "$ref": "#/responses/notFound"
+
+ opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
+
+ _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname"), opt.Data)
+ if err != nil {
+ if errors.Is(err, util.ErrInvalidArgument) {
+ ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err)
+ } else if errors.Is(err, util.ErrNotExist) {
+ ctx.Error(http.StatusNotFound, "CreateOrUpdateSecret", err)
+ } else {
+ ctx.Error(http.StatusInternalServerError, "CreateOrUpdateSecret", err)
+ }
+ return
+ }
+
+ if created {
+ ctx.Status(http.StatusCreated)
+ } else {
+ ctx.Status(http.StatusNoContent)
+ }
+}
+
+// DeleteSecret delete one secret of the organization
+func (Action) DeleteSecret(ctx *context.APIContext) {
+ // swagger:operation DELETE /orgs/{org}/actions/secrets/{secretname} organization deleteOrgSecret
+ // ---
+ // summary: Delete a secret in an organization
+ // consumes:
+ // - application/json
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: org
+ // in: path
+ // description: name of organization
+ // type: string
+ // required: true
+ // - name: secretname
+ // in: path
+ // description: name of the secret
+ // type: string
+ // required: true
+ // responses:
+ // "204":
+ // description: delete one secret of the organization
+ // "400":
+ // "$ref": "#/responses/error"
+ // "404":
+ // "$ref": "#/responses/notFound"
+
+ err := secret_service.DeleteSecretByName(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname"))
+ if err != nil {
+ if errors.Is(err, util.ErrInvalidArgument) {
+ ctx.Error(http.StatusBadRequest, "DeleteSecret", err)
+ } else if errors.Is(err, util.ErrNotExist) {
+ ctx.Error(http.StatusNotFound, "DeleteSecret", err)
+ } else {
+ ctx.Error(http.StatusInternalServerError, "DeleteSecret", err)
+ }
+ return
+ }
+
+ ctx.Status(http.StatusNoContent)
+}
+
+// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
+// GetRegistrationToken returns the token to register org runners
+func (Action) GetRegistrationToken(ctx *context.APIContext) {
+ // swagger:operation GET /orgs/{org}/actions/runners/registration-token organization orgGetRunnerRegistrationToken
+ // ---
+ // summary: Get an organization's actions runner registration token
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: org
+ // in: path
+ // description: name of the organization
+ // type: string
+ // required: true
+ // responses:
+ // "200":
+ // "$ref": "#/responses/RegistrationToken"
+
+ shared.GetRegistrationToken(ctx, ctx.Org.Organization.ID, 0)
+}
+
// ListVariables list org-level variables
-func ListVariables(ctx *context.APIContext) {
+func (Action) ListVariables(ctx *context.APIContext) {
// swagger:operation GET /orgs/{org}/actions/variables organization getOrgVariablesList
// ---
// summary: Get an org-level variables list
@@ -70,7 +242,7 @@ func ListVariables(ctx *context.APIContext) {
}
// GetVariable get an org-level variable
-func GetVariable(ctx *context.APIContext) {
+func (Action) GetVariable(ctx *context.APIContext) {
// swagger:operation GET /orgs/{org}/actions/variables/{variablename} organization getOrgVariable
// ---
// summary: Get an org-level variable
@@ -119,7 +291,7 @@ func GetVariable(ctx *context.APIContext) {
}
// DeleteVariable delete an org-level variable
-func DeleteVariable(ctx *context.APIContext) {
+func (Action) DeleteVariable(ctx *context.APIContext) {
// swagger:operation DELETE /orgs/{org}/actions/variables/{variablename} organization deleteOrgVariable
// ---
// summary: Delete an org-level variable
@@ -163,7 +335,7 @@ func DeleteVariable(ctx *context.APIContext) {
}
// CreateVariable create an org-level variable
-func CreateVariable(ctx *context.APIContext) {
+func (Action) CreateVariable(ctx *context.APIContext) {
// swagger:operation POST /orgs/{org}/actions/variables/{variablename} organization createOrgVariable
// ---
// summary: Create an org-level variable
@@ -227,7 +399,7 @@ func CreateVariable(ctx *context.APIContext) {
}
// UpdateVariable update an org-level variable
-func UpdateVariable(ctx *context.APIContext) {
+func (Action) UpdateVariable(ctx *context.APIContext) {
// swagger:operation PUT /orgs/{org}/actions/variables/{variablename} organization updateOrgVariable
// ---
// summary: Update an org-level variable
@@ -289,3 +461,13 @@ func UpdateVariable(ctx *context.APIContext) {
ctx.Status(http.StatusNoContent)
}
+
+var _ actions_service.API = new(Action)
+
+// Action implements actions_service.API
+type Action struct{}
+
+// NewAction creates a new Action service
+func NewAction() actions_service.API {
+ return Action{}
+}
diff --git a/routers/api/v1/org/runners.go b/routers/api/v1/org/runners.go
deleted file mode 100644
index 2a52bd8778..0000000000
--- a/routers/api/v1/org/runners.go
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package org
-
-import (
- "code.gitea.io/gitea/routers/api/v1/shared"
- "code.gitea.io/gitea/services/context"
-)
-
-// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
-
-// GetRegistrationToken returns the token to register org runners
-func GetRegistrationToken(ctx *context.APIContext) {
- // swagger:operation GET /orgs/{org}/actions/runners/registration-token organization orgGetRunnerRegistrationToken
- // ---
- // summary: Get an organization's actions runner registration token
- // produces:
- // - application/json
- // parameters:
- // - name: org
- // in: path
- // description: name of the organization
- // type: string
- // required: true
- // responses:
- // "200":
- // "$ref": "#/responses/RegistrationToken"
-
- shared.GetRegistrationToken(ctx, ctx.Org.Organization.ID, 0)
-}
diff --git a/routers/api/v1/org/secrets.go b/routers/api/v1/org/secrets.go
deleted file mode 100644
index abb6bb26c4..0000000000
--- a/routers/api/v1/org/secrets.go
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package org
-
-import (
- "errors"
- "net/http"
-
- "code.gitea.io/gitea/models/db"
- secret_model "code.gitea.io/gitea/models/secret"
- api "code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/util"
- "code.gitea.io/gitea/modules/web"
- "code.gitea.io/gitea/routers/api/v1/utils"
- "code.gitea.io/gitea/services/context"
- secret_service "code.gitea.io/gitea/services/secrets"
-)
-
-// ListActionsSecrets list an organization's actions secrets
-func ListActionsSecrets(ctx *context.APIContext) {
- // swagger:operation GET /orgs/{org}/actions/secrets organization orgListActionsSecrets
- // ---
- // summary: List an organization's actions secrets
- // produces:
- // - application/json
- // parameters:
- // - name: org
- // in: path
- // description: name of the organization
- // type: string
- // required: true
- // - name: page
- // in: query
- // description: page number of results to return (1-based)
- // type: integer
- // - name: limit
- // in: query
- // description: page size of results
- // type: integer
- // responses:
- // "200":
- // "$ref": "#/responses/SecretList"
- // "404":
- // "$ref": "#/responses/notFound"
-
- opts := &secret_model.FindSecretsOptions{
- OwnerID: ctx.Org.Organization.ID,
- ListOptions: utils.GetListOptions(ctx),
- }
-
- secrets, count, err := db.FindAndCount[secret_model.Secret](ctx, opts)
- if err != nil {
- ctx.InternalServerError(err)
- return
- }
-
- apiSecrets := make([]*api.Secret, len(secrets))
- for k, v := range secrets {
- apiSecrets[k] = &api.Secret{
- Name: v.Name,
- Created: v.CreatedUnix.AsTime(),
- }
- }
-
- ctx.SetTotalCountHeader(count)
- ctx.JSON(http.StatusOK, apiSecrets)
-}
-
-// create or update one secret of the organization
-func CreateOrUpdateSecret(ctx *context.APIContext) {
- // swagger:operation PUT /orgs/{org}/actions/secrets/{secretname} organization updateOrgSecret
- // ---
- // summary: Create or Update a secret value in an organization
- // consumes:
- // - application/json
- // produces:
- // - application/json
- // parameters:
- // - name: org
- // in: path
- // description: name of organization
- // type: string
- // required: true
- // - name: secretname
- // in: path
- // description: name of the secret
- // type: string
- // required: true
- // - name: body
- // in: body
- // schema:
- // "$ref": "#/definitions/CreateOrUpdateSecretOption"
- // responses:
- // "201":
- // description: response when creating a secret
- // "204":
- // description: response when updating a secret
- // "400":
- // "$ref": "#/responses/error"
- // "404":
- // "$ref": "#/responses/notFound"
-
- opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
-
- _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname"), opt.Data)
- if err != nil {
- if errors.Is(err, util.ErrInvalidArgument) {
- ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err)
- } else if errors.Is(err, util.ErrNotExist) {
- ctx.Error(http.StatusNotFound, "CreateOrUpdateSecret", err)
- } else {
- ctx.Error(http.StatusInternalServerError, "CreateOrUpdateSecret", err)
- }
- return
- }
-
- if created {
- ctx.Status(http.StatusCreated)
- } else {
- ctx.Status(http.StatusNoContent)
- }
-}
-
-// DeleteSecret delete one secret of the organization
-func DeleteSecret(ctx *context.APIContext) {
- // swagger:operation DELETE /orgs/{org}/actions/secrets/{secretname} organization deleteOrgSecret
- // ---
- // summary: Delete a secret in an organization
- // consumes:
- // - application/json
- // produces:
- // - application/json
- // parameters:
- // - name: org
- // in: path
- // description: name of organization
- // type: string
- // required: true
- // - name: secretname
- // in: path
- // description: name of the secret
- // type: string
- // required: true
- // responses:
- // "204":
- // description: delete one secret of the organization
- // "400":
- // "$ref": "#/responses/error"
- // "404":
- // "$ref": "#/responses/notFound"
-
- err := secret_service.DeleteSecretByName(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname"))
- if err != nil {
- if errors.Is(err, util.ErrInvalidArgument) {
- ctx.Error(http.StatusBadRequest, "DeleteSecret", err)
- } else if errors.Is(err, util.ErrNotExist) {
- ctx.Error(http.StatusNotFound, "DeleteSecret", err)
- } else {
- ctx.Error(http.StatusInternalServerError, "DeleteSecret", err)
- }
- return
- }
-
- ctx.Status(http.StatusNoContent)
-}
diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go
index 03321d956d..311cfca6e9 100644
--- a/routers/api/v1/repo/action.go
+++ b/routers/api/v1/repo/action.go
@@ -9,17 +9,76 @@ import (
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
+ secret_model "code.gitea.io/gitea/models/secret"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
+ "code.gitea.io/gitea/routers/api/v1/shared"
"code.gitea.io/gitea/routers/api/v1/utils"
actions_service "code.gitea.io/gitea/services/actions"
"code.gitea.io/gitea/services/context"
secret_service "code.gitea.io/gitea/services/secrets"
)
+// ListActionsSecrets list an repo's actions secrets
+func (Action) ListActionsSecrets(ctx *context.APIContext) {
+ // swagger:operation GET /repos/{owner}/{repo}/actions/secrets repository repoListActionsSecrets
+ // ---
+ // summary: List an repo's actions secrets
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: owner
+ // in: path
+ // description: owner of the repository
+ // type: string
+ // required: true
+ // - name: repo
+ // in: path
+ // description: name of the repository
+ // type: string
+ // required: true
+ // - name: page
+ // in: query
+ // description: page number of results to return (1-based)
+ // type: integer
+ // - name: limit
+ // in: query
+ // description: page size of results
+ // type: integer
+ // responses:
+ // "200":
+ // "$ref": "#/responses/SecretList"
+ // "404":
+ // "$ref": "#/responses/notFound"
+
+ repo := ctx.Repo.Repository
+
+ opts := &secret_model.FindSecretsOptions{
+ RepoID: repo.ID,
+ ListOptions: utils.GetListOptions(ctx),
+ }
+
+ secrets, count, err := db.FindAndCount[secret_model.Secret](ctx, opts)
+ if err != nil {
+ ctx.InternalServerError(err)
+ return
+ }
+
+ apiSecrets := make([]*api.Secret, len(secrets))
+ for k, v := range secrets {
+ apiSecrets[k] = &api.Secret{
+ Name: v.Name,
+ Created: v.CreatedUnix.AsTime(),
+ }
+ }
+
+ ctx.SetTotalCountHeader(count)
+ ctx.JSON(http.StatusOK, apiSecrets)
+}
+
// create or update one secret of the repository
-func CreateOrUpdateSecret(ctx *context.APIContext) {
+func (Action) CreateOrUpdateSecret(ctx *context.APIContext) {
// swagger:operation PUT /repos/{owner}/{repo}/actions/secrets/{secretname} repository updateRepoSecret
// ---
// summary: Create or Update a secret value in a repository
@@ -82,7 +141,7 @@ func CreateOrUpdateSecret(ctx *context.APIContext) {
}
// DeleteSecret delete one secret of the repository
-func DeleteSecret(ctx *context.APIContext) {
+func (Action) DeleteSecret(ctx *context.APIContext) {
// swagger:operation DELETE /repos/{owner}/{repo}/actions/secrets/{secretname} repository deleteRepoSecret
// ---
// summary: Delete a secret in a repository
@@ -133,7 +192,7 @@ func DeleteSecret(ctx *context.APIContext) {
}
// GetVariable get a repo-level variable
-func GetVariable(ctx *context.APIContext) {
+func (Action) GetVariable(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/actions/variables/{variablename} repository getRepoVariable
// ---
// summary: Get a repo-level variable
@@ -186,7 +245,7 @@ func GetVariable(ctx *context.APIContext) {
}
// DeleteVariable delete a repo-level variable
-func DeleteVariable(ctx *context.APIContext) {
+func (Action) DeleteVariable(ctx *context.APIContext) {
// swagger:operation DELETE /repos/{owner}/{repo}/actions/variables/{variablename} repository deleteRepoVariable
// ---
// summary: Delete a repo-level variable
@@ -235,7 +294,7 @@ func DeleteVariable(ctx *context.APIContext) {
}
// CreateVariable create a repo-level variable
-func CreateVariable(ctx *context.APIContext) {
+func (Action) CreateVariable(ctx *context.APIContext) {
// swagger:operation POST /repos/{owner}/{repo}/actions/variables/{variablename} repository createRepoVariable
// ---
// summary: Create a repo-level variable
@@ -302,7 +361,7 @@ func CreateVariable(ctx *context.APIContext) {
}
// UpdateVariable update a repo-level variable
-func UpdateVariable(ctx *context.APIContext) {
+func (Action) UpdateVariable(ctx *context.APIContext) {
// swagger:operation PUT /repos/{owner}/{repo}/actions/variables/{variablename} repository updateRepoVariable
// ---
// summary: Update a repo-level variable
@@ -369,7 +428,7 @@ func UpdateVariable(ctx *context.APIContext) {
}
// ListVariables list repo-level variables
-func ListVariables(ctx *context.APIContext) {
+func (Action) ListVariables(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/actions/variables repository getRepoVariablesList
// ---
// summary: Get repo-level variables list
@@ -423,3 +482,38 @@ func ListVariables(ctx *context.APIContext) {
ctx.SetTotalCountHeader(count)
ctx.JSON(http.StatusOK, variables)
}
+
+// GetRegistrationToken returns the token to register repo runners
+func (Action) GetRegistrationToken(ctx *context.APIContext) {
+ // swagger:operation GET /repos/{owner}/{repo}/runners/registration-token repository repoGetRunnerRegistrationToken
+ // ---
+ // summary: Get a repository's actions runner registration token
+ // 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/RegistrationToken"
+
+ shared.GetRegistrationToken(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.ID)
+}
+
+var _ actions_service.API = new(Action)
+
+// Action implements actions_service.API
+type Action struct{}
+
+// NewAction creates a new Action service
+func NewAction() actions_service.API {
+ return Action{}
+}
diff --git a/routers/api/v1/repo/runners.go b/routers/api/v1/repo/runners.go
deleted file mode 100644
index fe133b311d..0000000000
--- a/routers/api/v1/repo/runners.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package repo
-
-import (
- "code.gitea.io/gitea/routers/api/v1/shared"
- "code.gitea.io/gitea/services/context"
-)
-
-// GetRegistrationToken returns the token to register repo runners
-func GetRegistrationToken(ctx *context.APIContext) {
- // swagger:operation GET /repos/{owner}/{repo}/runners/registration-token repository repoGetRunnerRegistrationToken
- // ---
- // summary: Get a repository's actions runner registration token
- // 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/RegistrationToken"
-
- shared.GetRegistrationToken(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.ID)
-}
diff --git a/services/actions/interface.go b/services/actions/interface.go
new file mode 100644
index 0000000000..d4fa782fec
--- /dev/null
+++ b/services/actions/interface.go
@@ -0,0 +1,28 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package actions
+
+import "code.gitea.io/gitea/services/context"
+
+// API for actions of a repository or organization
+type API interface {
+ // ListActionsSecrets list secrets
+ ListActionsSecrets(*context.APIContext)
+ // CreateOrUpdateSecret create or update a secret
+ CreateOrUpdateSecret(*context.APIContext)
+ // DeleteSecret delete a secret
+ DeleteSecret(*context.APIContext)
+ // ListVariables list variables
+ ListVariables(*context.APIContext)
+ // GetVariable get a variable
+ GetVariable(*context.APIContext)
+ // DeleteVariable delete a variable
+ DeleteVariable(*context.APIContext)
+ // CreateVariable create a variable
+ CreateVariable(*context.APIContext)
+ // UpdateVariable update a variable
+ UpdateVariable(*context.APIContext)
+ // GetRegistrationToken get registration token
+ GetRegistrationToken(*context.APIContext)
+}
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index faf57454d7..3ed4e43e6d 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -3843,6 +3843,54 @@
}
}
},
+ "/repos/{owner}/{repo}/actions/secrets": {
+ "get": {
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "repository"
+ ],
+ "summary": "List an repo's actions secrets",
+ "operationId": "repoListActionsSecrets",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "owner of the repository",
+ "name": "owner",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "string",
+ "description": "name of the repository",
+ "name": "repo",
+ "in": "path",
+ "required": true
+ },
+ {
+ "type": "integer",
+ "description": "page number of results to return (1-based)",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "page size of results",
+ "name": "limit",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/responses/SecretList"
+ },
+ "404": {
+ "$ref": "#/responses/notFound"
+ }
+ }
+ }
+ },
"/repos/{owner}/{repo}/actions/secrets/{secretname}": {
"put": {
"consumes": [
diff --git a/tests/integration/api_repo_secrets_test.go b/tests/integration/api_repo_secrets_test.go
index feb9bae2b2..c3074d9ece 100644
--- a/tests/integration/api_repo_secrets_test.go
+++ b/tests/integration/api_repo_secrets_test.go
@@ -24,6 +24,12 @@ func TestAPIRepoSecrets(t *testing.T) {
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
+ t.Run("List", func(t *testing.T) {
+ req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/secrets", repo.FullName())).
+ AddTokenAuth(token)
+ MakeRequest(t, req, http.StatusOK)
+ })
+
t.Run("Create", func(t *testing.T) {
cases := []struct {
Name string
@@ -31,7 +37,7 @@ func TestAPIRepoSecrets(t *testing.T) {
}{
{
Name: "",
- ExpectedStatus: http.StatusNotFound,
+ ExpectedStatus: http.StatusMethodNotAllowed,
},
{
Name: "-",