Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support configuration variables on Gitea Actions #24724

Merged
merged 83 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from 81 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
c88e2ad
implements varibales
sillyguodong Apr 23, 2023
427dfa2
typo
sillyguodong Apr 23, 2023
3c0aa03
Merge branch 'main' into feature/variables
sillyguodong Apr 23, 2023
5edf8ae
fix context package
sillyguodong Apr 23, 2023
9e860db
Merge branch 'main' into feature/variables
sillyguodong Apr 28, 2023
fbe232f
Merge branch 'main' into feature/variables
sillyguodong May 5, 2023
a438e97
update
sillyguodong May 8, 2023
b018fee
fix lint
sillyguodong May 8, 2023
fd6270c
complete
sillyguodong May 8, 2023
54d4918
lint
sillyguodong May 8, 2023
e19b2fe
lint
sillyguodong May 8, 2023
b1bf9a8
Merge branch 'main' into feature/variables
sillyguodong May 8, 2023
e1051a3
fmt check
sillyguodong May 8, 2023
89928e9
typo
sillyguodong May 8, 2023
4007170
typo
sillyguodong May 8, 2023
0e37460
Merge branch 'main' into feature/variables
sillyguodong May 10, 2023
bcaba8b
reanme table name
sillyguodong May 10, 2023
a580e4a
delete unnecessary where condition
sillyguodong May 15, 2023
de5cbbc
Merge branch 'main' into feature/variables
sillyguodong May 15, 2023
6c28158
delete
sillyguodong May 15, 2023
4081980
use button-ghost class
sillyguodong May 15, 2023
460ba32
add padding for list items
sillyguodong May 16, 2023
8867d20
user level variables
sillyguodong May 16, 2023
06eec8b
use fetch request
sillyguodong May 19, 2023
ae965db
await json
sillyguodong May 19, 2023
5e2bf96
Merge branch 'main' into feature/variables
sillyguodong May 22, 2023
e69f537
lint
sillyguodong May 22, 2023
e2a7327
make fmt
sillyguodong May 22, 2023
45165e4
rename filename and function name
sillyguodong May 24, 2023
fc9b3fa
delete comment
sillyguodong May 24, 2023
ba90273
Merge branch 'main' into feature/variables
sillyguodong May 24, 2023
3b9d874
getValidateContext
sillyguodong May 24, 2023
c0552dd
fix path param
sillyguodong May 24, 2023
7c184d5
fix jquery.are-you-sure interference
silverwind May 28, 2023
238418d
modal fixes
silverwind May 28, 2023
0d07e9c
rename field, use ignore-dirty
silverwind May 28, 2023
2029461
simplify form validation
silverwind May 28, 2023
2ba6a92
use flexbox, fix border-radius
silverwind May 28, 2023
57d9e70
Merge branch 'main' into feature/variables
sillyguodong Jun 6, 2023
795cd09
fix secrets list
sillyguodong Jun 8, 2023
bb7e455
action modal share js
sillyguodong Jun 8, 2023
83a593d
Update options/locale/locale_en-US.ini
sillyguodong Jun 8, 2023
945efc2
make check
sillyguodong Jun 8, 2023
b1f5d83
lint
sillyguodong Jun 9, 2023
e632c97
Merge branch 'main' into feature/variables
sillyguodong Jun 9, 2023
d849c9e
fix actions meun
sillyguodong Jun 12, 2023
a75d1f6
Merge branch 'main' into feature/variables
sillyguodong Jun 12, 2023
5da62b4
update
sillyguodong Jun 13, 2023
ad2b53f
fix
sillyguodong Jun 13, 2023
8928823
fix
sillyguodong Jun 13, 2023
2a4d05f
Merge branch 'main' into feature/variables
sillyguodong Jun 15, 2023
935a579
lint-templates
sillyguodong Jun 15, 2023
5811563
no index
sillyguodong Jun 16, 2023
cea22db
interact-bg
sillyguodong Jun 16, 2023
2506e95
update
sillyguodong Jun 16, 2023
791983f
init
sillyguodong Jun 16, 2023
cc2c282
delete space
sillyguodong Jun 16, 2023
27ded72
keep index of repo_id
sillyguodong Jun 16, 2023
fb0681f
modal onApprove
sillyguodong Jun 16, 2023
1d65fad
delete show-modal class
sillyguodong Jun 16, 2023
905e916
Merge branch 'main' into feature/variables
wxiaoguang Jun 16, 2023
058dcc8
fix fmt
wxiaoguang Jun 16, 2023
8e9a11a
use link-action
sillyguodong Jun 16, 2023
81d62c5
prepare to use general "show-modal"
wxiaoguang Jun 16, 2023
f766a4b
delete useless key class
sillyguodong Jun 16, 2023
1134fc6
use gt-rounded-bottom
sillyguodong Jun 16, 2023
e87c2c3
refactor
wxiaoguang Jun 16, 2023
14467cb
fine tune
wxiaoguang Jun 16, 2023
bc8f7ae
fix modal background for loading state
silverwind Jun 16, 2023
403090d
move comment
silverwind Jun 16, 2023
0339408
clean tooltip
sillyguodong Jun 16, 2023
0738c17
Update options/locale/locale_en-US.ini
sillyguodong Jun 16, 2023
9f618a3
delete unused trans
sillyguodong Jun 16, 2023
06b1f39
add top-level trans
sillyguodong Jun 16, 2023
48e9368
Merge branch 'main' into feature/variables
wxiaoguang Jun 18, 2023
9a43909
Merge branch 'main' into feature/variables
silverwind Jun 18, 2023
3c47977
rename column
sillyguodong Jun 19, 2023
d8abde9
forbid env name ci
sillyguodong Jun 19, 2023
2d80878
make fmt
sillyguodong Jun 19, 2023
aff6008
Merge branch 'main' into feature/variables
sillyguodong Jun 19, 2023
b22af4d
Merge branch 'main' into feature/variables
sillyguodong Jun 19, 2023
d0f6c54
fix max char count of name and data
sillyguodong Jun 20, 2023
58e9253
Merge branch 'main' into feature/variables
GiteaBot Jun 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions models/actions/variable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package actions

import (
"context"
"errors"
"fmt"
"strings"

"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"

"xorm.io/builder"
)

type ActionVariable struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"UNIQUE(owner_repo_name)"`
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name)"`
Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"`
Data string `xorm:"LONGTEXT NOT NULL"`
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
}

func init() {
db.RegisterModel(new(ActionVariable))
}

func (v *ActionVariable) Validate() error {
if v.OwnerID == 0 && v.RepoID == 0 {
return errors.New("the variable is not bound to any scope")
}
return nil
}

func InsertVariable(ctx context.Context, ownerID, repoID int64, name, data string) (*ActionVariable, error) {
variable := &ActionVariable{
OwnerID: ownerID,
RepoID: repoID,
Name: strings.ToUpper(name),
Data: data,
}
if err := variable.Validate(); err != nil {
return variable, err
}
return variable, db.Insert(ctx, variable)
}

type FindVariablesOpts struct {
db.ListOptions
OwnerID int64
RepoID int64
}

func (opts *FindVariablesOpts) toConds() builder.Cond {
cond := builder.NewCond()
if opts.OwnerID > 0 {
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
sillyguodong marked this conversation as resolved.
Show resolved Hide resolved
}
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
}
return cond
}

func FindVariables(ctx context.Context, opts FindVariablesOpts) ([]*ActionVariable, error) {
var variables []*ActionVariable
sess := db.GetEngine(ctx)
if opts.PageSize != 0 {
sess = db.SetSessionPagination(sess, &opts.ListOptions)
}
return variables, sess.Where(opts.toConds()).Find(&variables)
}

func GetVariableByID(ctx context.Context, variableID int64) (*ActionVariable, error) {
var variable ActionVariable
has, err := db.GetEngine(ctx).Where("id=?", variableID).Get(&variable)
if err != nil {
return nil, err
} else if !has {
return nil, fmt.Errorf("variable with id %d: %w", variableID, util.ErrNotExist)
}
return &variable, nil
}

func UpdateVariable(ctx context.Context, variable *ActionVariable) (bool, error) {
count, err := db.GetEngine(ctx).ID(variable.ID).Cols("name", "data").
Update(&ActionVariable{
Name: variable.Name,
Data: variable.Data,
})
return count != 0, err
}
3 changes: 3 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,9 @@ var migrations = []Migration{

// v260 -> v261
NewMigration("Drop custom_labels column of action_runner table", v1_21.DropCustomLabelsColumnOfActionRunner),

// v261 -> v262
NewMigration("Add variable table", v1_21.CreateVariableTable),
}

// GetCurrentDBVersion returns the current db version
Expand Down
24 changes: 24 additions & 0 deletions models/migrations/v1_21/v261.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_21 //nolint

import (
"code.gitea.io/gitea/modules/timeutil"

"xorm.io/xorm"
)

func CreateVariableTable(x *xorm.Engine) error {
type ActionVariable struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"UNIQUE(owner_repo_name)"`
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name)"`
Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"`
Data string `xorm:"LONGTEXT NOT NULL"`
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
}

return x.Sync(new(ActionVariable))
}
42 changes: 4 additions & 38 deletions models/secret/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,17 @@ package secret

import (
"context"
"fmt"
"regexp"
"errors"
"strings"

"code.gitea.io/gitea/models/db"
secret_module "code.gitea.io/gitea/modules/secret"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"

"xorm.io/builder"
)

type ErrSecretInvalidValue struct {
Name *string
Data *string
}

func (err ErrSecretInvalidValue) Error() string {
if err.Name != nil {
return fmt.Sprintf("secret name %q is invalid", *err.Name)
}
if err.Data != nil {
return fmt.Sprintf("secret data %q is invalid", *err.Data)
}
return util.ErrInvalidArgument.Error()
}

func (err ErrSecretInvalidValue) Unwrap() error {
return util.ErrInvalidArgument
}

// Secret represents a secret
type Secret struct {
ID int64
Expand Down Expand Up @@ -74,24 +53,11 @@ func init() {
db.RegisterModel(new(Secret))
}

var (
secretNameReg = regexp.MustCompile("^[A-Z_][A-Z0-9_]*$")
forbiddenSecretPrefixReg = regexp.MustCompile("^GIT(EA|HUB)_")
)

// Validate validates the required fields and formats.
func (s *Secret) Validate() error {
switch {
case len(s.Name) == 0 || len(s.Name) > 50:
return ErrSecretInvalidValue{Name: &s.Name}
case len(s.Data) == 0:
return ErrSecretInvalidValue{Data: &s.Data}
case !secretNameReg.MatchString(s.Name) ||
forbiddenSecretPrefixReg.MatchString(s.Name):
return ErrSecretInvalidValue{Name: &s.Name}
default:
return nil
if s.OwnerID == 0 && s.RepoID == 0 {
return errors.New("the secret is not bound to any scope")
}
return nil
}

type FindSecretsOptions struct {
Expand Down
21 changes: 19 additions & 2 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ show_full_screen = Show full screen

confirm_delete_selected = Confirm to delete all selected items?

name = Name
value = Value

[aria]
navbar = Navigation Bar
footer = Footer
Expand Down Expand Up @@ -3391,8 +3394,6 @@ owner.settings.chef.keypair.description = Generate a key pair used to authentica
secrets = Secrets
description = Secrets will be passed to certain actions and cannot be read otherwise.
none = There are no secrets yet.
value = Value
name = Name
creation = Add Secret
creation.name_placeholder = case-insensitive, alphanumeric characters or underscores only, cannot start with GITEA_ or GITHUB_
creation.value_placeholder = Input any content. Whitespace at the start and end will be omitted.
Expand Down Expand Up @@ -3462,6 +3463,22 @@ runs.no_matching_runner_helper = No matching runner: %s

need_approval_desc = Need approval to run workflows for fork pull request.

variables = Variables
variables.management = Variables Management
variables.creation = Add Variable
variables.none = There are no variables yet.
variables.deletion = Remove variable
variables.deletion.description = Removing a variable is permanent and cannot be undone. Continue?
variables.description = Variables will be passed to certain actions and cannot be read otherwise.
variables.id_not_exist = Variable with id %d not exists.
variables.edit = Edit Variable
variables.deletion.failed = Failed to remove variable.
variables.deletion.success = The variable has been removed.
variables.creation.failed = Failed to add variable.
variables.creation.success = The variable "%s" has been added.
variables.update.failed = Failed to edit variable.
variables.update.success = The variable has been edited.

[projects]
type-1.display_name = Individual Project
type-2.display_name = Repository Project
Expand Down
24 changes: 24 additions & 0 deletions routers/api/actions/runner/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func pickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv
WorkflowPayload: t.Job.WorkflowPayload,
Context: generateTaskContext(t),
Secrets: getSecretsOfTask(ctx, t),
Vars: getVariablesOfTask(ctx, t),
}

if needs, err := findTaskNeeds(ctx, t); err != nil {
Expand Down Expand Up @@ -88,6 +89,29 @@ func getSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) map[s
return secrets
}

func getVariablesOfTask(ctx context.Context, task *actions_model.ActionTask) map[string]string {
variables := map[string]string{}

// Org / User level
ownerVariables, err := actions_model.FindVariables(ctx, actions_model.FindVariablesOpts{OwnerID: task.Job.Run.Repo.OwnerID})
if err != nil {
log.Error("find variables of org: %d, error: %v", task.Job.Run.Repo.OwnerID, err)
}

// Repo level
repoVariables, err := actions_model.FindVariables(ctx, actions_model.FindVariablesOpts{RepoID: task.Job.Run.RepoID})
if err != nil {
log.Error("find variables of repo: %d, error: %v", task.Job.Run.RepoID, err)
}

// Level precedence: Repo > Org / User
for _, v := range append(ownerVariables, repoVariables...) {
variables[v.Name] = v.Data
}

return variables
}

func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
event := map[string]interface{}{}
_ = json.Unmarshal([]byte(t.Job.Run.EventPayload), &event)
Expand Down
6 changes: 6 additions & 0 deletions routers/web/repo/setting/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ func SecretsPost(ctx *context.Context) {
ctx.ServerError("getSecretsCtx", err)
return
}

if ctx.HasError() {
ctx.JSONError(ctx.GetErrMsg())
return
}

shared.PerformSecretsPost(
ctx,
sCtx.OwnerID,
Expand Down
Loading