From fe76a035ad75ef9167a87ef0e3088868521a0bf0 Mon Sep 17 00:00:00 2001 From: sillyguodong Date: Mon, 12 Jun 2023 06:54:17 +0000 Subject: [PATCH] Follow upstream support for `variables` (#66) Because the upstream [PR](https://github.com/nektos/act/pull/1833) already supports variables, so this PR revert #43 (commit de529139af), and cherry-pick commit [6ce45e3](https://github.com/nektos/act/commit/6ce45e3f246f12d6617691de9a2423920d5fdbe6). Co-authored-by: Kuan Yong Reviewed-on: https://gitea.com/gitea/act/pulls/66 Reviewed-by: Jason Song Co-authored-by: sillyguodong Co-committed-by: sillyguodong --- cmd/input.go | 6 ++++++ cmd/root.go | 7 +++++++ pkg/exprparser/interpreter.go | 8 ++++---- pkg/exprparser/interpreter_test.go | 4 ++++ pkg/jobparser/interpeter.go | 2 -- pkg/runner/expression.go | 10 ++++++---- pkg/runner/expression_test.go | 10 ++++++++++ pkg/runner/run_context.go | 4 ---- pkg/runner/runner.go | 2 +- 9 files changed, 38 insertions(+), 15 deletions(-) diff --git a/cmd/input.go b/cmd/input.go index ed9655c..954018f 100644 --- a/cmd/input.go +++ b/cmd/input.go @@ -16,6 +16,7 @@ type Input struct { reuseContainers bool bindWorkdir bool secrets []string + vars []string envs []string inputs []string platforms []string @@ -26,6 +27,7 @@ type Input struct { envfile string inputfile string secretfile string + varfile string insecureSecrets bool defaultBranch string privileged bool @@ -78,6 +80,10 @@ func (i *Input) Secretfile() string { return i.resolve(i.secretfile) } +func (i *Input) Varfile() string { + return i.resolve(i.varfile) +} + // Workdir returns path to workdir func (i *Input) Workdir() string { return i.resolve(".") diff --git a/cmd/root.go b/cmd/root.go index d5b8c39..ba1f31d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -49,6 +49,7 @@ func Execute(ctx context.Context, version string) { rootCmd.Flags().StringVar(&input.remoteName, "remote-name", "origin", "git remote name that will be used to retrieve url of git repo") rootCmd.Flags().StringArrayVarP(&input.secrets, "secret", "s", []string{}, "secret to make available to actions with optional value (e.g. -s mysecret=foo or -s mysecret)") + rootCmd.Flags().StringArrayVar(&input.vars, "var", []string{}, "variable to make available to actions with optional value (e.g. --var myvar=foo or --var myvar)") rootCmd.Flags().StringArrayVarP(&input.envs, "env", "", []string{}, "env to make available to actions with optional value (e.g. --env myenv=foo or --env myenv)") rootCmd.Flags().StringArrayVarP(&input.inputs, "input", "", []string{}, "action input to make available to actions (e.g. --input myinput=foo)") rootCmd.Flags().StringArrayVarP(&input.platforms, "platform", "P", []string{}, "custom image to use per platform (e.g. -P ubuntu-18.04=nektos/act-environments-ubuntu:18.04)") @@ -77,6 +78,7 @@ func Execute(ctx context.Context, version string) { rootCmd.PersistentFlags().BoolVarP(&input.noOutput, "quiet", "q", false, "disable logging of output from steps") rootCmd.PersistentFlags().BoolVarP(&input.dryrun, "dryrun", "n", false, "dryrun mode") rootCmd.PersistentFlags().StringVarP(&input.secretfile, "secret-file", "", ".secrets", "file with list of secrets to read from (e.g. --secret-file .secrets)") + rootCmd.PersistentFlags().StringVarP(&input.varfile, "var-file", "", ".vars", "file with list of vars to read from (e.g. --var-file .vars)") rootCmd.PersistentFlags().BoolVarP(&input.insecureSecrets, "insecure-secrets", "", false, "NOT RECOMMENDED! Doesn't hide secrets while printing logs.") rootCmd.PersistentFlags().StringVarP(&input.envfile, "env-file", "", ".env", "environment file to read and use as env in the containers") rootCmd.PersistentFlags().StringVarP(&input.inputfile, "input-file", "", ".input", "input file to read and use as action input") @@ -418,6 +420,10 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str secrets := newSecrets(input.secrets) _ = readEnvs(input.Secretfile(), secrets) + log.Debugf("Loading vars from %s", input.Varfile()) + vars := newSecrets(input.vars) + _ = readEnvs(input.Varfile(), vars) + matrixes := parseMatrix(input.matrix) log.Debugf("Evaluated matrix inclusions: %v", matrixes) @@ -579,6 +585,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str JSONLogger: input.jsonLogger, Env: envs, Secrets: secrets, + Vars: vars, Inputs: inputs, Token: secrets["GITHUB_TOKEN"], InsecureSecrets: input.insecureSecrets, diff --git a/pkg/exprparser/interpreter.go b/pkg/exprparser/interpreter.go index 5a6d48f..b30c0b7 100644 --- a/pkg/exprparser/interpreter.go +++ b/pkg/exprparser/interpreter.go @@ -19,12 +19,11 @@ type EvaluationEnvironment struct { Steps map[string]*model.StepResult Runner map[string]interface{} Secrets map[string]string + Vars map[string]string Strategy map[string]interface{} Matrix map[string]interface{} Needs map[string]Needs Inputs map[string]interface{} - - Vars map[string]string } type Needs struct { @@ -150,6 +149,7 @@ func (impl *interperterImpl) evaluateNode(exprNode actionlint.ExprNode) (interfa } } +// nolint:gocyclo func (impl *interperterImpl) evaluateVariable(variableNode *actionlint.VariableNode) (interface{}, error) { switch strings.ToLower(variableNode.Name) { case "github": @@ -171,6 +171,8 @@ func (impl *interperterImpl) evaluateVariable(variableNode *actionlint.VariableN return impl.env.Runner, nil case "secrets": return impl.env.Secrets, nil + case "vars": + return impl.env.Vars, nil case "strategy": return impl.env.Strategy, nil case "matrix": @@ -183,8 +185,6 @@ func (impl *interperterImpl) evaluateVariable(variableNode *actionlint.VariableN return math.Inf(1), nil case "nan": return math.NaN(), nil - case "vars": - return impl.env.Vars, nil default: return nil, fmt.Errorf("Unavailable context: %s", variableNode.Name) } diff --git a/pkg/exprparser/interpreter_test.go b/pkg/exprparser/interpreter_test.go index 01eb25f..f45851d 100644 --- a/pkg/exprparser/interpreter_test.go +++ b/pkg/exprparser/interpreter_test.go @@ -557,6 +557,7 @@ func TestContexts(t *testing.T) { // {"contains(steps.*.outputs.name, 'value')", true, "steps-context-array-outputs"}, {"runner.os", "Linux", "runner-context"}, {"secrets.name", "value", "secrets-context"}, + {"vars.name", "value", "vars-context"}, {"strategy.fail-fast", true, "strategy-context"}, {"matrix.os", "Linux", "matrix-context"}, {"needs.job-id.outputs.output-name", "value", "needs-context"}, @@ -593,6 +594,9 @@ func TestContexts(t *testing.T) { Secrets: map[string]string{ "name": "value", }, + Vars: map[string]string{ + "name": "value", + }, Strategy: map[string]interface{}{ "fail-fast": true, }, diff --git a/pkg/jobparser/interpeter.go b/pkg/jobparser/interpeter.go index a29a4ee..750f964 100644 --- a/pkg/jobparser/interpeter.go +++ b/pkg/jobparser/interpeter.go @@ -62,8 +62,6 @@ func NewInterpeter( Matrix: matrix, Needs: using, Inputs: nil, // not supported yet - - Vars: nil, } config := exprparser.Config{ diff --git a/pkg/runner/expression.go b/pkg/runner/expression.go index ce4f748..5a9872f 100644 --- a/pkg/runner/expression.go +++ b/pkg/runner/expression.go @@ -77,12 +77,11 @@ func (rc *RunContext) NewExpressionEvaluatorWithEnv(ctx context.Context, env map // but required to interpolate/evaluate the step outputs on the job Steps: rc.getStepsContext(), Secrets: getWorkflowSecrets(ctx, rc), + Vars: getWorkflowVars(ctx, rc), Strategy: strategy, Matrix: rc.Matrix, Needs: using, Inputs: inputs, - - Vars: rc.getVarsContext(), } if rc.JobContainer != nil { ee.Runner = rc.JobContainer.GetRunnerContext(ctx) @@ -126,14 +125,13 @@ func (rc *RunContext) NewStepExpressionEvaluator(ctx context.Context, step step) Job: rc.getJobContext(), Steps: rc.getStepsContext(), Secrets: getWorkflowSecrets(ctx, rc), + Vars: getWorkflowVars(ctx, rc), Strategy: strategy, Matrix: rc.Matrix, Needs: using, // todo: should be unavailable // but required to interpolate/evaluate the inputs in actions/composite Inputs: inputs, - - Vars: rc.getVarsContext(), } if rc.JobContainer != nil { ee.Runner = rc.JobContainer.GetRunnerContext(ctx) @@ -426,3 +424,7 @@ func getWorkflowSecrets(ctx context.Context, rc *RunContext) map[string]string { return rc.Config.Secrets } + +func getWorkflowVars(ctx context.Context, rc *RunContext) map[string]string { + return rc.Config.Vars +} diff --git a/pkg/runner/expression_test.go b/pkg/runner/expression_test.go index 283b6cf..5cc2f7b 100644 --- a/pkg/runner/expression_test.go +++ b/pkg/runner/expression_test.go @@ -28,6 +28,9 @@ func createRunContext(t *testing.T) *RunContext { Secrets: map[string]string{ "CASE_INSENSITIVE_SECRET": "value", }, + Vars: map[string]string{ + "CASE_INSENSITIVE_VAR": "value", + }, }, Env: map[string]string{ "key": "value", @@ -122,6 +125,8 @@ func TestEvaluateRunContext(t *testing.T) { {"env.key", "value", ""}, {"secrets.CASE_INSENSITIVE_SECRET", "value", ""}, {"secrets.case_insensitive_secret", "value", ""}, + {"vars.CASE_INSENSITIVE_VAR", "value", ""}, + {"vars.case_insensitive_var", "value", ""}, {"format('{{0}}', 'test')", "{0}", ""}, {"format('{{{0}}}', 'test')", "{test}", ""}, {"format('}}')", "}", ""}, @@ -195,6 +200,9 @@ func TestInterpolate(t *testing.T) { Secrets: map[string]string{ "CASE_INSENSITIVE_SECRET": "value", }, + Vars: map[string]string{ + "CASE_INSENSITIVE_VAR": "value", + }, }, Env: map[string]string{ "KEYWITHNOTHING": "valuewithnothing", @@ -229,6 +237,8 @@ func TestInterpolate(t *testing.T) { {" ${{ env.KEY_WITH_UNDERSCORES }} ", " value_with_underscores "}, {"${{ secrets.CASE_INSENSITIVE_SECRET }}", "value"}, {"${{ secrets.case_insensitive_secret }}", "value"}, + {"${{ vars.CASE_INSENSITIVE_VAR }}", "value"}, + {"${{ vars.case_insensitive_var }}", "value"}, {"${{ env.UNKNOWN }}", ""}, {"${{ env.SOMETHING_TRUE }}", "true"}, {"${{ env.SOMETHING_FALSE }}", "false"}, diff --git a/pkg/runner/run_context.go b/pkg/runner/run_context.go index 4a7e11e..13b0765 100644 --- a/pkg/runner/run_context.go +++ b/pkg/runner/run_context.go @@ -739,10 +739,6 @@ func (rc *RunContext) getStepsContext() map[string]*model.StepResult { return rc.StepResults } -func (rc *RunContext) getVarsContext() map[string]string { - return rc.Config.Vars -} - func (rc *RunContext) getGithubContext(ctx context.Context) *model.GithubContext { logger := common.Logger(ctx) ghc := &model.GithubContext{ diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index 0ede98a..55a71ef 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -36,6 +36,7 @@ type Config struct { Env map[string]string // env for containers Inputs map[string]string // manually passed action inputs Secrets map[string]string // list of secrets + Vars map[string]string // list of vars Token string // GitHub token InsecureSecrets bool // switch hiding output when printing to terminal Platforms map[string]string // list of platforms @@ -67,7 +68,6 @@ type Config struct { DefaultActionsURLs []string // urls from gitea's `DEFAULT_ACTIONS_URL` config PlatformPicker func(labels []string) string // platform picker, it will take precedence over Platforms if isn't nil JobLoggerLevel *log.Level // the level of job logger - Vars map[string]string // the list of variables set at the repository, environment, or organization levels. ValidVolumes []string // only volumes (and bind mounts) in this slice can be mounted on the job container or service containers }