新增:secret和variable查询

This commit is contained in:
yystopf 2025-12-01 19:29:09 +08:00 committed by xxq250
parent 5059a43874
commit ee5d35490f
11 changed files with 893 additions and 6 deletions

View File

@ -22,7 +22,7 @@ import (
)
var (
Version = "v2.8.6, by v1.21.0, 20251111 "
Version = "v2.8.7, by v1.21.0, 20251201 "
Tags = ""
MakeVersion = ""
)

59
models/actions/secret.go Normal file
View File

@ -0,0 +1,59 @@
package actions
import (
"context"
"strings"
"code.gitea.io/gitea/models/db"
secret_model "code.gitea.io/gitea/models/secret"
"xorm.io/builder"
)
type FindSecretsOptions struct {
db.ListOptions
OwnerID int64
RepoID int64
SecretID int64
Name string
}
func (opts *FindSecretsOptions) toConds() builder.Cond {
cond := builder.NewCond()
if opts.OwnerID > 0 {
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
}
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
}
if opts.SecretID != 0 {
cond = cond.And(builder.Eq{"id": opts.SecretID})
}
if opts.Name != "" {
cond = cond.And(builder.Eq{"name": strings.ToUpper(opts.Name)})
}
return cond
}
func FindSecrets(ctx context.Context, opts FindSecretsOptions) ([]*secret_model.Secret, error) {
var secrets []*secret_model.Secret
sess := db.GetEngine(ctx)
if opts.PageSize != 0 {
sess = db.SetSessionPagination(sess, &opts.ListOptions)
}
return secrets, sess.
Where(opts.toConds()).
OrderBy("created_unix desc").
Find(&secrets)
}
func CountSecrets(ctx context.Context, opts *FindSecretsOptions) (int64, error) {
return db.GetEngine(ctx).Where(opts.toConds()).Count(new(secret_model.Secret))
}
func DeleteSecret(ctx context.Context, secret *secret_model.Secret) error {
if _, err := db.DeleteByID(ctx, secret.ID, secret); err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,65 @@
package actions
import (
"context"
"strings"
gitea_actions "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
"xorm.io/builder"
)
type FindVariablesOpts struct {
db.ListOptions
IDs []int64
RepoID int64
OwnerID int64 // it will be ignored if RepoID is set
Name string
}
func (opts FindVariablesOpts) ToConds() builder.Cond {
cond := builder.NewCond()
if len(opts.IDs) > 0 {
if len(opts.IDs) == 1 {
cond = cond.And(builder.Eq{"id": opts.IDs[0]})
} else {
cond = cond.And(builder.In("id", opts.IDs))
}
}
// Since we now support instance-level variables,
// there is no need to check for null values for `owner_id` and `repo_id`
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
if opts.RepoID != 0 { // if RepoID is set
// ignore OwnerID and treat it as 0
cond = cond.And(builder.Eq{"owner_id": 0})
} else {
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
}
if opts.Name != "" {
cond = cond.And(builder.Eq{"name": strings.ToUpper(opts.Name)})
}
return cond
}
func FindVariables(ctx context.Context, opts FindVariablesOpts) ([]*gitea_actions.ActionVariable, error) {
var variables []*gitea_actions.ActionVariable
sess := db.GetEngine(ctx)
if opts.PageSize != 0 {
sess = db.SetSessionPagination(sess, &opts.ListOptions)
}
return variables, sess.Where(opts.ToConds()).OrderBy("created_unix desc").Find(&variables)
}
func CountVariables(ctx context.Context, opts FindVariablesOpts) (int64, error) {
sess := db.GetEngine(ctx)
return sess.Where(opts.ToConds()).Count(new(gitea_actions.ActionVariable))
}
func DeleteVariable(ctx context.Context, variable *gitea_actions.ActionVariable) error {
if _, err := db.DeleteByID(ctx, variable.ID, variable); err != nil {
return err
}
return nil
}

34
modules/structs/secret.go Normal file
View File

@ -0,0 +1,34 @@
package structs
import "time"
// CreateVariableOption the option when creating variable
// swagger:model
type CreateSecretOption struct {
// Value of the variable to create
//
// required: true
Data string `json:"data" binding:"Required"`
}
// UpdateVariableOption the option when updating variable
// swagger:model
type UpdateSecretOption struct {
// New name for the variable. If the field is empty, the variable name won't be updated.
Name string `json:"name"`
// Value of the variable to update
//
// required: true
Data string `json:"data" binding:"Required"`
// Description of the variable to update
}
// Secret represents a secret
// swagger:model
type Secret struct {
// the secret's name
Name string `json:"name"`
// swagger:strfmt date-time
Created time.Time `json:"created_at"`
}

View File

@ -0,0 +1,36 @@
package structs
// CreateVariableOption the option when creating variable
// swagger:model
type CreateVariableOption struct {
// Value of the variable to create
//
// required: true
Value string `json:"value" binding:"Required"`
}
// UpdateVariableOption the option when updating variable
// swagger:model
type UpdateVariableOption struct {
// New name for the variable. If the field is empty, the variable name won't be updated.
Name string `json:"name"`
// Value of the variable to update
//
// required: true
Value string `json:"value" binding:"Required"`
// Description of the variable to update
}
// ActionVariable return value of the query API
// swagger:model
type ActionVariable struct {
// the owner to which the variable belongs
OwnerID int64 `json:"owner_id"`
// the repository to which the variable belongs
RepoID int64 `json:"repo_id"`
// the name of the variable
Name string `json:"name"`
// the value of the variable
Data string `json:"data"`
}

12
modules/util/util.go Normal file
View File

@ -0,0 +1,12 @@
package util
import "strings"
func ReserveLineBreakForTextarea(input string) string {
// Since the content is from a form which is a textarea, the line endings are \r\n.
// It's a standard behavior of HTML.
// But we want to store them as \n like what GitHub does.
// And users are unlikely to really need to keep the \r.
// Other than this, we should respect the original content, even leading or trailing spaces.
return strings.ReplaceAll(input, "\r\n", "\n")
}

View File

@ -133,7 +133,21 @@ func Routers() *web.Route {
m.Get("/code", context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode), repo.Code)
m.Combo("").Delete(reqToken(), reqOwner(), repo.Delete)
m.Group("/actions", func() {
m.Get("/secrets", context.ReferencesGitRepo(), actions.ListActionsSecrets)
m.Group("/secrets", func() {
m.Get("", reqToken(), reqAdmin(), actions.ListActionsSecrets)
m.Combo("/{secretname}").
Delete(reqToken(), reqAdmin(), actions.DeleteActionsSecret).
Post(reqToken(), reqAdmin(), bind(hat_api.CreateSecretOption{}), actions.CreateActionsSecret).
Put(reqToken(), reqAdmin(), bind(hat_api.UpdateSecretOption{}), actions.UpdateActionsSecret)
})
m.Group("/variables", func() {
m.Get("", reqToken(), reqAdmin(), actions.ListVariables)
m.Combo("/{variablename}").
Get(reqToken(), reqAdmin(), actions.GetVariable).
Delete(reqToken(), reqAdmin(), actions.DeleteVariable).
Post(reqToken(), reqAdmin(), bind(hat_api.CreateVariableOption{}), actions.CreateVariable).
Put(reqToken(), reqAdmin(), bind(hat_api.UpdateVariableOption{}), actions.UpdateVariable)
})
m.Get("", context.ReferencesGitRepo(), actions.ListActions)
m.Post("/disable", reqAdmin(), actions.DisableWorkflowFile)
m.Post("/enable", reqAdmin(), actions.EnableWorkflowFile)
@ -253,6 +267,23 @@ func Routers() *web.Route {
m.Post("/orgs", reqToken(), bind(gitea_api.CreateOrgOption{}), org.Create)
m.Group("/orgs/{org}", func() {
m.Combo("").Patch(reqToken(), reqOrgOwnership(), bind(hat_api.EditOrgOption{}), org.Edit)
m.Group("/actions", func() {
m.Group("/secrets", func() {
m.Get("", reqToken(), reqAdmin(), org.ListActionsSecrets)
m.Combo("/{secretname}").
Delete(reqToken(), reqAdmin(), org.DeleteActionsSecret).
Post(reqToken(), reqAdmin(), bind(hat_api.CreateSecretOption{}), org.CreateActionsSecret).
Put(reqToken(), reqAdmin(), bind(hat_api.UpdateSecretOption{}), org.UpdateActionsSecret)
})
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(hat_api.CreateVariableOption{}), org.CreateVariable).
Put(reqToken(), reqOrgOwnership(), bind(hat_api.UpdateVariableOption{}), org.UpdateVariable)
})
})
}, orgAssignment(true))
m.Group("/teams/{teamid}", func() {

261
routers/hat/org/action.go Normal file
View File

@ -0,0 +1,261 @@
package org
import (
"errors"
"net/http"
"code.gitea.io/gitea/modules/context"
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"
hat_actions_model "code.gitlink.org.cn/Gitlink/gitea_hat.git/models/actions"
hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
hat_actions_service "code.gitlink.org.cn/Gitlink/gitea_hat.git/services/actions"
)
func DeleteActionsSecret(ctx *context.APIContext) {
if err := hat_actions_service.DeleteSecretByName(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname")); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.Error(http.StatusBadRequest, "DeleteSecretByName", err)
} else if errors.Is(err, util.ErrNotExist) {
ctx.NotFound(err)
} else {
ctx.InternalServerError(err)
}
return
}
ctx.Status(http.StatusNoContent)
}
func CreateActionsSecret(ctx *context.APIContext) {
opt := web.GetForm(ctx).(*hat_api.CreateSecretOption)
ownerID := ctx.Org.Organization.ID
secretName := ctx.Params("secretname")
v, err := hat_actions_service.GetSecret(ctx, hat_actions_model.FindSecretsOptions{
OwnerID: ownerID,
Name: secretName,
})
if err != nil && !errors.Is(err, util.ErrNotExist) {
ctx.InternalServerError(err)
return
}
if v != nil && v.ID > 0 {
ctx.Error(http.StatusConflict, "", util.NewAlreadyExistErrorf("secret name %s already exists", secretName))
return
}
if _, err := hat_actions_service.CreateSecret(ctx, ownerID, 0, secretName, opt.Data); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.Error(http.StatusBadRequest, "CreateSecret", err)
} else {
ctx.InternalServerError(err)
}
return
}
ctx.Status(http.StatusCreated)
}
func UpdateActionsSecret(ctx *context.APIContext) {
opt := web.GetForm(ctx).(*hat_api.UpdateSecretOption)
_, err := hat_actions_service.GetSecret(ctx, hat_actions_model.FindSecretsOptions{
OwnerID: ctx.Org.Organization.ID,
Name: ctx.Params("secretname"),
})
if err != nil {
if errors.Is(err, util.ErrNotExist) {
ctx.Error(http.StatusNotFound, "GetSecret", err)
} else {
ctx.InternalServerError(err)
}
return
}
if opt.Name == "" {
opt.Name = ctx.Params("secretname")
}
_, err = hat_actions_service.UpdateSecret(ctx, ctx.Org.Organization.ID, 0, opt.Name, opt.Data)
if err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.Error(http.StatusBadRequest, "UpdateSecret", err)
} else {
ctx.InternalServerError(err)
}
return
}
ctx.Status(http.StatusNoContent)
}
func ListActionsSecrets(ctx *context.APIContext) {
opts := &hat_actions_model.FindSecretsOptions{
OwnerID: ctx.Org.Organization.ID,
ListOptions: utils.GetListOptions(ctx),
}
count, err := hat_actions_model.CountSecrets(ctx, opts)
if err != nil {
ctx.InternalServerError(err)
return
}
secrets, err := hat_actions_model.FindSecrets(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)
}
func GetVariable(ctx *context.APIContext) {
v, err := hat_actions_service.GetVariable(ctx, hat_actions_model.FindVariablesOpts{
OwnerID: ctx.Org.Organization.ID,
Name: ctx.Params("variablename"),
})
if err != nil {
if errors.Is(err, util.ErrNotExist) {
ctx.NotFound(err)
} else {
ctx.InternalServerError(err)
}
return
}
variable := &hat_api.ActionVariable{
OwnerID: v.OwnerID,
RepoID: v.RepoID,
Name: v.Name,
Data: v.Data,
}
ctx.JSON(http.StatusOK, variable)
}
func DeleteVariable(ctx *context.APIContext) {
if err := hat_actions_service.DeleteVariableByName(ctx, ctx.Org.Organization.ID, 0, ctx.Params("variablename")); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.Error(http.StatusBadRequest, "DeleteVariableByName", err)
} else if errors.Is(err, util.ErrNotExist) {
ctx.NotFound(err)
} else {
ctx.InternalServerError(err)
}
return
}
ctx.Status(http.StatusNoContent)
}
func CreateVariable(ctx *context.APIContext) {
opt := web.GetForm(ctx).(*hat_api.CreateVariableOption)
ownerID := ctx.Org.Organization.ID
variableName := ctx.Params("variablename")
v, err := hat_actions_service.GetVariable(ctx, hat_actions_model.FindVariablesOpts{
OwnerID: ownerID,
Name: variableName,
})
if err != nil && !errors.Is(err, util.ErrNotExist) {
ctx.InternalServerError(err)
return
}
if v != nil && v.ID > 0 {
ctx.Error(http.StatusConflict, "", util.NewAlreadyExistErrorf("variable name %s already exists", variableName))
return
}
if _, err := hat_actions_service.CreateVariable(ctx, ownerID, 0, variableName, opt.Value); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.Error(http.StatusBadRequest, "CreateVariable", err)
} else {
ctx.InternalServerError(err)
}
return
}
ctx.Status(http.StatusCreated)
}
func UpdateVariable(ctx *context.APIContext) {
opt := web.GetForm(ctx).(*hat_api.UpdateVariableOption)
v, err := hat_actions_service.GetVariable(ctx, hat_actions_model.FindVariablesOpts{
OwnerID: ctx.Org.Organization.ID,
Name: ctx.Params("variablename"),
})
if err != nil {
if errors.Is(err, util.ErrNotExist) {
ctx.Error(http.StatusNotFound, "GetVariable", err)
} else {
ctx.InternalServerError(err)
}
return
}
if opt.Name == "" {
opt.Name = ctx.Params("variablename")
}
v.Name = opt.Name
v.Data = opt.Value
if _, err := hat_actions_service.UpdateVariableNameData(ctx, v); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.Error(http.StatusBadRequest, "UpdateVariableNameData", err)
} else {
ctx.InternalServerError(err)
}
return
}
ctx.Status(http.StatusNoContent)
}
func ListVariables(ctx *context.APIContext) {
opts := hat_actions_model.FindVariablesOpts{
OwnerID: ctx.Org.Organization.ID,
ListOptions: utils.GetListOptions(ctx),
}
vars, err := hat_actions_model.FindVariables(ctx, opts)
if err != nil {
ctx.InternalServerError(err)
return
}
count, err := hat_actions_model.CountVariables(ctx, opts)
if err != nil {
ctx.InternalServerError(err)
return
}
variables := make([]*hat_api.ActionVariable, len(vars))
for i, v := range vars {
variables[i] = &hat_api.ActionVariable{
OwnerID: v.OwnerID,
RepoID: v.RepoID,
Name: v.Name,
Data: v.Data,
}
}
ctx.SetTotalCountHeader(count)
ctx.JSON(http.StatusOK, variables)
}

View File

@ -15,7 +15,6 @@ import (
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
secret_model "code.gitea.io/gitea/models/secret"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/actions"
@ -32,24 +31,103 @@ import (
actions_service "code.gitea.io/gitea/services/actions"
"code.gitea.io/gitea/services/convert"
hat_actions_model "code.gitlink.org.cn/Gitlink/gitea_hat.git/models/actions"
hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
hat_actions_service "code.gitlink.org.cn/Gitlink/gitea_hat.git/services/actions"
jobparser "github.com/nektos/act/pkg/jobparser"
"github.com/nektos/act/pkg/model"
"xorm.io/builder"
)
func DeleteActionsSecret(ctx *context.APIContext) {
if err := hat_actions_service.DeleteSecretByName(ctx, 0, ctx.Repo.Repository.ID, ctx.Params("secretname")); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.Error(http.StatusBadRequest, "DeleteSecretByName", err)
} else if errors.Is(err, util.ErrNotExist) {
ctx.NotFound(err)
} else {
ctx.InternalServerError(err)
}
return
}
ctx.Status(http.StatusNoContent)
}
func CreateActionsSecret(ctx *context.APIContext) {
opt := web.GetForm(ctx).(*hat_api.CreateSecretOption)
repoID := ctx.Repo.Repository.ID
secretName := ctx.Params("secretname")
v, err := hat_actions_service.GetSecret(ctx, hat_actions_model.FindSecretsOptions{
RepoID: repoID,
Name: secretName,
})
if err != nil && !errors.Is(err, util.ErrNotExist) {
ctx.InternalServerError(err)
return
}
if v != nil && v.ID > 0 {
ctx.Error(http.StatusConflict, "", util.NewAlreadyExistErrorf("secret name %s already exists", secretName))
return
}
if _, err := hat_actions_service.CreateSecret(ctx, 0, repoID, secretName, opt.Data); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.Error(http.StatusBadRequest, "CreateSecret", err)
} else {
ctx.InternalServerError(err)
}
return
}
ctx.Status(http.StatusCreated)
}
func UpdateActionsSecret(ctx *context.APIContext) {
opt := web.GetForm(ctx).(*hat_api.UpdateSecretOption)
_, err := hat_actions_service.GetSecret(ctx, hat_actions_model.FindSecretsOptions{
RepoID: ctx.Repo.Repository.ID,
Name: ctx.Params("secretname"),
})
if err != nil {
if errors.Is(err, util.ErrNotExist) {
ctx.Error(http.StatusNotFound, "GetSecret", err)
} else {
ctx.InternalServerError(err)
}
return
}
if opt.Name == "" {
opt.Name = ctx.Params("secretname")
}
_, err = hat_actions_service.UpdateSecret(ctx, 0, ctx.Repo.Repository.ID, opt.Name, opt.Data)
if err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.Error(http.StatusBadRequest, "UpdateSecret", err)
} else {
ctx.InternalServerError(err)
}
return
}
ctx.Status(http.StatusNoContent)
}
func ListActionsSecrets(ctx *context.APIContext) {
opts := &secret_model.FindSecretsOptions{
opts := &hat_actions_model.FindSecretsOptions{
RepoID: ctx.Repo.Repository.ID,
ListOptions: utils.GetListOptions(ctx),
}
count, err := secret_model.CountSecrets(ctx, opts)
count, err := hat_actions_model.CountSecrets(ctx, opts)
if err != nil {
ctx.InternalServerError(err)
return
}
secrets, err := secret_model.FindSecrets(ctx, *opts)
secrets, err := hat_actions_model.FindSecrets(ctx, *opts)
if err != nil {
ctx.InternalServerError(err)
return
@ -67,6 +145,143 @@ func ListActionsSecrets(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, apiSecrets)
}
func GetVariable(ctx *context.APIContext) {
v, err := hat_actions_service.GetVariable(ctx, hat_actions_model.FindVariablesOpts{
RepoID: ctx.Repo.Repository.ID,
Name: ctx.Params("variablename"),
})
if err != nil {
if errors.Is(err, util.ErrNotExist) {
ctx.NotFound(err)
} else {
ctx.InternalServerError(err)
}
return
}
variable := &hat_api.ActionVariable{
OwnerID: v.OwnerID,
RepoID: v.RepoID,
Name: v.Name,
Data: v.Data,
}
ctx.JSON(http.StatusOK, variable)
}
func DeleteVariable(ctx *context.APIContext) {
if err := hat_actions_service.DeleteVariableByName(ctx, 0, ctx.Repo.Repository.ID, ctx.Params("variablename")); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.Error(http.StatusBadRequest, "DeleteVariableByName", err)
} else if errors.Is(err, util.ErrNotExist) {
ctx.NotFound(err)
} else {
ctx.InternalServerError(err)
}
return
}
ctx.Status(http.StatusNoContent)
}
func CreateVariable(ctx *context.APIContext) {
opt := web.GetForm(ctx).(*hat_api.CreateVariableOption)
repoID := ctx.Repo.Repository.ID
variableName := ctx.Params("variablename")
v, err := hat_actions_service.GetVariable(ctx, hat_actions_model.FindVariablesOpts{
RepoID: repoID,
Name: variableName,
})
if err != nil && !errors.Is(err, util.ErrNotExist) {
ctx.InternalServerError(err)
return
}
if v != nil && v.ID > 0 {
ctx.Error(http.StatusConflict, "", util.NewAlreadyExistErrorf("variable name %s already exists", variableName))
return
}
if _, err := hat_actions_service.CreateVariable(ctx, 0, repoID, variableName, opt.Value); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.Error(http.StatusBadRequest, "CreateVariable", err)
} else {
ctx.InternalServerError(err)
}
return
}
ctx.Status(http.StatusCreated)
}
func UpdateVariable(ctx *context.APIContext) {
opt := web.GetForm(ctx).(*hat_api.UpdateVariableOption)
v, err := hat_actions_service.GetVariable(ctx, hat_actions_model.FindVariablesOpts{
RepoID: ctx.Repo.Repository.ID,
Name: ctx.Params("variablename"),
})
if err != nil {
if errors.Is(err, util.ErrNotExist) {
ctx.Error(http.StatusNotFound, "GetVariable", err)
} else {
ctx.InternalServerError(err)
}
return
}
if opt.Name == "" {
opt.Name = ctx.Params("variablename")
}
v.Name = opt.Name
v.Data = opt.Value
if _, err := hat_actions_service.UpdateVariableNameData(ctx, v); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.Error(http.StatusBadRequest, "UpdateVariableNameData", err)
} else {
ctx.InternalServerError(err)
}
return
}
ctx.Status(http.StatusNoContent)
}
func ListVariables(ctx *context.APIContext) {
opts := hat_actions_model.FindVariablesOpts{
RepoID: ctx.Repo.Repository.ID,
ListOptions: utils.GetListOptions(ctx),
}
vars, err := hat_actions_model.FindVariables(ctx, opts)
if err != nil {
ctx.InternalServerError(err)
return
}
count, err := hat_actions_model.CountVariables(ctx, opts)
if err != nil {
ctx.InternalServerError(err)
return
}
variables := make([]*hat_api.ActionVariable, len(vars))
for i, v := range vars {
variables[i] = &hat_api.ActionVariable{
OwnerID: v.OwnerID,
RepoID: v.RepoID,
Name: v.Name,
Data: v.Data,
}
}
ctx.SetTotalCountHeader(count)
ctx.JSON(http.StatusOK, variables)
}
func Run(ctx *context.APIContext) {
workflow := ctx.FormString("workflow")
ref := ctx.FormString("ref")

105
services/actions/secrets.go Normal file
View File

@ -0,0 +1,105 @@
package actions
import (
"context"
"regexp"
"strings"
"sync"
secret_model "code.gitea.io/gitea/models/secret"
hat_actions_model "code.gitlink.org.cn/Gitlink/gitea_hat.git/models/actions"
"code.gitea.io/gitea/modules/util"
)
var globalVars = sync.OnceValue(func() (ret struct {
namePattern, forbiddenPrefixPattern *regexp.Regexp
},
) {
ret.namePattern = regexp.MustCompile("(?i)^[A-Z_][A-Z0-9_]*$")
ret.forbiddenPrefixPattern = regexp.MustCompile("(?i)^GIT(EA|HUB)_")
return ret
})
func ValidateName(name string) error {
vars := globalVars()
if !vars.namePattern.MatchString(name) ||
vars.forbiddenPrefixPattern.MatchString(name) ||
strings.EqualFold(name, "CI") /* CI is always set to true in GitHub Actions*/ {
return util.NewInvalidArgumentErrorf("invalid variable or secret name")
}
return nil
}
func CreateSecret(ctx context.Context, ownerID, repoID int64, name, data string) (*secret_model.Secret, error) {
if err := ValidateName(name); err != nil {
return nil, err
}
s, err := secret_model.InsertEncryptedSecret(ctx, ownerID, repoID, name, data)
if err != nil {
return nil, err
}
return s, nil
}
func UpdateSecret(ctx context.Context, ownerID, repoID int64, name, data string) (bool, error) {
if err := ValidateName(name); err != nil {
return false, err
}
s, err := GetSecret(ctx, hat_actions_model.FindSecretsOptions{
OwnerID: ownerID,
RepoID: repoID,
Name: name,
})
if err != nil {
return false, err
}
if s == nil {
return false, util.NewNotExistErrorf("secret not found")
}
err = secret_model.UpdateSecret(ctx, s.ID, data)
if err != nil {
return false, err
}
return true, nil
}
func GetSecret(ctx context.Context, opts hat_actions_model.FindSecretsOptions) (*secret_model.Secret, error) {
vars, err := hat_actions_model.FindSecrets(ctx, opts)
if err != nil {
return nil, err
}
if len(vars) != 1 {
return nil, util.NewNotExistErrorf("variable not found")
}
return vars[0], nil
}
func DeleteSecretByName(ctx context.Context, ownerID, repoID int64, name string) error {
s, err := GetSecret(ctx, hat_actions_model.FindSecretsOptions{
OwnerID: ownerID,
RepoID: repoID,
Name: name,
})
if err != nil {
return err
}
return hat_actions_model.DeleteSecret(ctx, s)
}
func DeleteSecretByID(ctx context.Context, secretID int64) error {
s, err := GetSecret(ctx, hat_actions_model.FindSecretsOptions{
SecretID: secretID,
})
if err != nil {
return err
}
return hat_actions_model.DeleteSecret(ctx, s)
}

View File

@ -0,0 +1,69 @@
package actions
import (
"context"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/modules/util"
secret_service "code.gitea.io/gitea/services/secrets"
hat_actions_model "code.gitlink.org.cn/Gitlink/gitea_hat.git/models/actions"
hat_util "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/util"
)
func CreateVariable(ctx context.Context, ownerID, repoID int64, name, data string) (*actions_model.ActionVariable, error) {
if err := secret_service.ValidateName(name); err != nil {
return nil, err
}
v, err := actions_model.InsertVariable(ctx, ownerID, repoID, name, hat_util.ReserveLineBreakForTextarea(data))
if err != nil {
return nil, err
}
return v, nil
}
func UpdateVariableNameData(ctx context.Context, variable *actions_model.ActionVariable) (bool, error) {
if err := secret_service.ValidateName(variable.Name); err != nil {
return false, err
}
variable.Data = hat_util.ReserveLineBreakForTextarea(variable.Data)
return actions_model.UpdateVariable(ctx, variable)
}
func DeleteVariableByID(ctx context.Context, variableID int64) error {
v, err := GetVariable(ctx, hat_actions_model.FindVariablesOpts{
IDs: []int64{variableID},
})
if err != nil {
return err
}
return hat_actions_model.DeleteVariable(ctx, v)
}
func DeleteVariableByName(ctx context.Context, ownerID, repoID int64, name string) error {
v, err := GetVariable(ctx, hat_actions_model.FindVariablesOpts{
OwnerID: ownerID,
RepoID: repoID,
Name: name,
})
if err != nil {
return err
}
return hat_actions_model.DeleteVariable(ctx, v)
}
func GetVariable(ctx context.Context, opts hat_actions_model.FindVariablesOpts) (*actions_model.ActionVariable, error) {
vars, err := hat_actions_model.FindVariables(ctx, opts)
if err != nil {
return nil, err
}
if len(vars) != 1 {
return nil, util.NewNotExistErrorf("variable not found")
}
return vars[0], nil
}