- 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>tags/v1.22.0-rc1
@@ -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). |
@@ -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{} | |||
} |
@@ -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) | |||
} |
@@ -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) | |||
} |
@@ -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{} | |||
} |
@@ -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) | |||
} |
@@ -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) | |||
} |
@@ -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": [ |
@@ -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: "-", |