Compare commits

2 Commits

Author SHA1 Message Date
Lunny Xiao
e23fda0aca fix: keep env evaluator in sync
Co-Authored-By: Codet (GPT-5) <codet@commitgo.dev>
2026-04-27 14:25:06 -07:00
Lunny Xiao
66a723f9a6 fix: preserve job env for steps
Co-Authored-By: Codet (GPT-5) <codet@commitgo.dev>
2026-04-27 14:05:24 -07:00
3 changed files with 74 additions and 9 deletions

View File

@@ -78,13 +78,20 @@ func (rc *RunContext) String() string {
// GetEnv returns the env for the context // GetEnv returns the env for the context
func (rc *RunContext) GetEnv() map[string]string { func (rc *RunContext) GetEnv() map[string]string {
baseEnv := map[string]string{}
if rc.Run != nil && rc.Run.Workflow != nil && rc.Config != nil {
job := rc.Run.Job()
if job != nil {
baseEnv = mergeMaps(rc.Run.Workflow.Env, job.Environment(), rc.Config.Env)
}
}
if rc.Env == nil { if rc.Env == nil {
rc.Env = map[string]string{} rc.Env = map[string]string{}
if rc.Run != nil && rc.Run.Workflow != nil && rc.Config != nil { }
job := rc.Run.Job() for k, v := range baseEnv {
if job != nil { if _, ok := rc.Env[k]; !ok {
rc.Env = mergeMaps(rc.Run.Workflow.Env, job.Environment(), rc.Config.Env) rc.Env[k] = v
}
} }
} }
rc.Env["ACT"] = "true" rc.Env["ACT"] = "true"

View File

@@ -572,6 +572,10 @@ if: false`, ""),
} }
func TestRunContextGetEnv(t *testing.T) { func TestRunContextGetEnv(t *testing.T) {
var jobEnv yaml.Node
err := jobEnv.Encode(map[string]string{"JOB_ONLY": "job-value"})
assert.NoError(t, err) //nolint:testifylint // pre-existing issue from nektos/act
tests := []struct { tests := []struct {
description string description string
rc *RunContext rc *RunContext
@@ -612,6 +616,26 @@ func TestRunContextGetEnv(t *testing.T) {
targetEnv: "OVERWRITTEN", targetEnv: "OVERWRITTEN",
want: "false", want: "false",
}, },
{
description: "Pre-populated run context env should still include job env",
rc: &RunContext{
Config: &Config{},
Env: map[string]string{
"RUNTIME_ONLY": "true",
},
Run: &model.Run{
JobID: "test",
Workflow: &model.Workflow{
Jobs: map[string]*model.Job{"test": {
Name: "test",
Env: jobEnv,
}},
},
},
},
targetEnv: "JOB_ONLY",
want: "job-value",
},
} }
for _, test := range tests { for _, test := range tests {
@@ -622,6 +646,37 @@ func TestRunContextGetEnv(t *testing.T) {
} }
} }
func TestRunContextGetEnvKeepsExpressionEvaluatorEnvCurrent(t *testing.T) {
var jobEnv yaml.Node
err := jobEnv.Encode(map[string]string{"JOB_ONLY": "job-value"})
assert.NoError(t, err) //nolint:testifylint // pre-existing issue from nektos/act
rc := &RunContext{
Config: &Config{},
Env: map[string]string{
"RUNTIME_ONLY": "true",
},
Run: &model.Run{
JobID: "test",
Workflow: &model.Workflow{
Jobs: map[string]*model.Job{"test": {
Name: "test",
Env: jobEnv,
}},
},
},
}
rc.ExprEval = rc.NewExpressionEvaluator(context.Background())
rc.GetEnv()
rc.setEnv(context.Background(), map[string]string{"name": "STEP_TIMEOUT"}, "0")
got, evalErr := rc.ExprEval.evaluate(context.Background(), "env.STEP_TIMEOUT", exprparser.DefaultStatusCheckNone)
assert.NoError(t, evalErr) //nolint:testifylint // pre-existing issue from nektos/act
assert.EqualValues(t, "0", got)
assert.EqualValues(t, "job-value", rc.Env["JOB_ONLY"]) //nolint:testifylint // pre-existing issue from nektos/act
}
func Test_createSimpleContainerName(t *testing.T) { func Test_createSimpleContainerName(t *testing.T) {
tests := []struct { tests := []struct {
parts []string parts []string

View File

@@ -120,6 +120,10 @@ func TestSetupEnv(t *testing.T) {
cm := &containerMock{} cm := &containerMock{}
sm := &stepMock{} sm := &stepMock{}
var jobEnv yaml.Node
err := jobEnv.Encode(map[string]string{"JOB_KEY": "jobvalue"})
assert.NoError(t, err) //nolint:testifylint // pre-existing issue from nektos/act
rc := &RunContext{ rc := &RunContext{
Config: &Config{ Config: &Config{
Env: map[string]string{ Env: map[string]string{
@@ -131,9 +135,7 @@ func TestSetupEnv(t *testing.T) {
Workflow: &model.Workflow{ Workflow: &model.Workflow{
Jobs: map[string]*model.Job{ Jobs: map[string]*model.Job{
"1": { "1": {
Env: yaml.Node{ Env: jobEnv,
Value: "JOB_KEY: jobvalue",
},
}, },
}, },
}, },
@@ -155,7 +157,7 @@ func TestSetupEnv(t *testing.T) {
sm.On("getStepModel").Return(step) sm.On("getStepModel").Return(step)
sm.On("getEnv").Return(&env) sm.On("getEnv").Return(&env)
err := setupEnv(context.Background(), sm) err = setupEnv(context.Background(), sm)
assert.Nil(t, err) //nolint:testifylint // pre-existing issue from nektos/act assert.Nil(t, err) //nolint:testifylint // pre-existing issue from nektos/act
// These are commit or system specific // These are commit or system specific
@@ -191,6 +193,7 @@ func TestSetupEnv(t *testing.T) {
"GITHUB_SERVER_URL": "https://", "GITHUB_SERVER_URL": "https://",
"GITHUB_WORKFLOW": "", "GITHUB_WORKFLOW": "",
"INPUT_STEP_WITH": "with-value", "INPUT_STEP_WITH": "with-value",
"JOB_KEY": "jobvalue",
"RC_KEY": "rcvalue", "RC_KEY": "rcvalue",
"RUNNER_PERFLOG": "/dev/null", "RUNNER_PERFLOG": "/dev/null",
"RUNNER_TRACKING_ID": "", "RUNNER_TRACKING_ID": "",