mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-11-02 13:27:16 +08:00
enhance: add GITEA_* aliases for built-in workflow environment variables (#1358)
Closes https://gitea.com/gitea/runner/issues/1317, which makes https://github.com/go-gitea/gitea/issues/39813 redundant as the runner sets these variables. Every built-in `GITHUB_*` environment variable the runner sets is now also available as `GITEA_*` with the same value, so Gitea-native workflows don't have to rely on GitHub naming. The `GITEA_*` names mirror the `GITHUB_*` ones after their last write, so they stay equal and are unset together. Workflow, job and runner `envs` values for these `GITEA_*` names are now overwritten, the same as for `GITHUB_*`. --------- Co-authored-by: silverwind <me@silverwind.io> Reviewed-on: https://gitea.com/gitea/runner/pulls/1358 Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com> Co-authored-by: KenanZhu <imnanoki@qq.com>
This commit is contained in:
@@ -456,6 +456,7 @@ func evalDockerEnv(ctx context.Context, step step, action *model.Action) (*expre
|
||||
}
|
||||
}
|
||||
mergeIntoMap(step, step.getEnv(), runsEnv, maps.Clone(*step.getEnv()))
|
||||
aliasGiteaEnv(*step.getEnv())
|
||||
return ee, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
func TestCompositeActionParity(t *testing.T) {
|
||||
t.Run("input defaults use the step identity", func(t *testing.T) {
|
||||
t.Run("input defaults use the step identity and docker env keeps the GITEA aliases", func(t *testing.T) {
|
||||
for _, uses := range []string{"./action", "own/action@v2"} {
|
||||
t.Run(uses, func(t *testing.T) {
|
||||
rc := &RunContext{
|
||||
@@ -33,13 +33,17 @@ func TestCompositeActionParity(t *testing.T) {
|
||||
currentStep = &stepActionRemote{RunContext: rc, Step: &model.Step{Uses: uses}, env: map[string]string{}, remoteAction: mustNewRemoteAction(t, uses)}
|
||||
want = "own/action|v2"
|
||||
}
|
||||
action := &model.Action{Inputs: map[string]model.Input{"identity": {Default: "${{ github.action_repository }}|${{ github.action_ref }}"}}}
|
||||
action := &model.Action{
|
||||
Inputs: map[string]model.Input{"identity": {Default: "${{ github.action_repository }}|${{ github.action_ref }}"}},
|
||||
Runs: model.ActionRuns{Env: map[string]string{"GITHUB_WORKFLOW_SHA": "runs-sha"}},
|
||||
}
|
||||
require.NoError(t, setupEnv(t.Context(), currentStep))
|
||||
require.NoError(t, populateEnvsFromInput(t.Context(), currentStep, action))
|
||||
assert.Equal(t, want, (*currentStep.getEnv())["INPUT_IDENTITY"])
|
||||
_, err := evalDockerEnv(t.Context(), currentStep, action)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, want, (*currentStep.getEnv())["identity"])
|
||||
assert.Equal(t, "runs-sha", (*currentStep.getEnv())["GITEA_WORKFLOW_SHA"])
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -84,8 +84,7 @@ func (rc *RunContext) setupHookFileCommands(ctx context.Context, env map[string]
|
||||
actPath := rc.JobContainer.GetActPath()
|
||||
env["GITHUB_ENV"] = path.Join(actPath, hookEnvFileCommand)
|
||||
env["GITHUB_PATH"] = path.Join(actPath, hookPathFileCommand)
|
||||
env["GITEA_ENV"] = env["GITHUB_ENV"]
|
||||
env["GITEA_PATH"] = env["GITHUB_PATH"]
|
||||
aliasGiteaEnv(env)
|
||||
|
||||
return rc.JobContainer.Copy(actPath,
|
||||
&container.FileEntry{Name: hookEnvFileCommand, Mode: 0o666},
|
||||
|
||||
@@ -121,6 +121,7 @@ func TestRunJobHook(t *testing.T) {
|
||||
assert.Equal(t, "job", jobContainer.env["GITHUB_JOB"])
|
||||
assert.Equal(t, "/var/run/act/workflow/hook-envs.txt", jobContainer.env["GITHUB_ENV"])
|
||||
assert.Equal(t, "/var/run/act/workflow/hook-path.txt", jobContainer.env["GITHUB_PATH"])
|
||||
assert.Equal(t, jobContainer.env["GITHUB_PATH"], jobContainer.env["GITEA_PATH"])
|
||||
})
|
||||
|
||||
t.Run("each hook has its own command state", func(t *testing.T) {
|
||||
|
||||
@@ -1602,6 +1602,23 @@ func isLocalCheckout(ghc *model.GithubContext, step *model.Step) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// aliasGiteaEnv mirrors the runner's GITHUB_* variables as GITEA_*, call it after the last write to them.
|
||||
func aliasGiteaEnv(env map[string]string) {
|
||||
for _, suffix := range []string{
|
||||
"ACTION", "ACTION_PATH", "ACTION_REF", "ACTION_REPOSITORY", "ACTIONS", "ACTOR", "ACTOR_ID", "API_URL", "BASE_REF",
|
||||
"ENV", "EVENT_NAME", "EVENT_PATH", "GRAPHQL_URL", "HEAD_REF", "JOB", "OUTPUT", "PATH", "REF", "REF_NAME",
|
||||
"REF_PROTECTED", "REF_TYPE", "REPOSITORY", "REPOSITORY_ID", "REPOSITORY_OWNER", "REPOSITORY_OWNER_ID",
|
||||
"RETENTION_DAYS", "RUN_ATTEMPT", "RUN_ID", "RUN_NUMBER", "SERVER_URL", "SHA", "STATE", "STEP_SUMMARY",
|
||||
"TRIGGERING_ACTOR", "WORKFLOW", "WORKFLOW_REF", "WORKFLOW_SHA", "WORKSPACE",
|
||||
} {
|
||||
if value, ok := env["GITHUB_"+suffix]; ok {
|
||||
env["GITEA_"+suffix] = value
|
||||
} else {
|
||||
delete(env, "GITEA_"+suffix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (rc *RunContext) withGithubEnv(ctx context.Context, github *model.GithubContext, env map[string]string) {
|
||||
if _, ok := env["CI"]; !ok {
|
||||
env["CI"] = "true"
|
||||
@@ -1654,6 +1671,7 @@ func (rc *RunContext) withGithubEnv(ctx context.Context, github *model.GithubCon
|
||||
|
||||
env["GITHUB_GRAPHQL_URL"] = ""
|
||||
env["GITHUB_RUN_ATTEMPT"] = github.RunAttempt
|
||||
aliasGiteaEnv(env)
|
||||
|
||||
env["RUNNER_NAME"] = rc.Config.RunnerName
|
||||
env["RUNNER_ENVIRONMENT"] = "self-hosted"
|
||||
|
||||
@@ -877,25 +877,25 @@ func TestGetGitHubContext(t *testing.T) {
|
||||
RepositoryID: "34",
|
||||
RepositoryOwnerID: "56",
|
||||
WorkflowRef: "owner/repo/.gitea/workflows/test.yml@refs/heads/main",
|
||||
WorkflowSha: "workflow-sha",
|
||||
RefProtected: true,
|
||||
}
|
||||
ghc = rc.getGithubContext(t.Context())
|
||||
assert.Equal(t, "preset-actor", ghc.Actor)
|
||||
assert.Equal(t, "triggerer", ghc.TriggeringActor)
|
||||
assert.Equal(t, "job1", ghc.Job)
|
||||
env := map[string]string{}
|
||||
env := map[string]string{"GITHUB_WORKFLOW_SHA": "workflow-sha"}
|
||||
rc.withGithubEnv(t.Context(), ghc, env)
|
||||
for name, value := range map[string]string{
|
||||
"GITHUB_ACTOR_ID": "12",
|
||||
"GITHUB_TRIGGERING_ACTOR": "triggerer",
|
||||
"GITHUB_REPOSITORY_ID": "34",
|
||||
"GITHUB_REPOSITORY_OWNER_ID": "56",
|
||||
"GITHUB_WORKFLOW_REF": "owner/repo/.gitea/workflows/test.yml@refs/heads/main",
|
||||
"GITHUB_WORKFLOW_SHA": "workflow-sha",
|
||||
"GITHUB_REF_PROTECTED": "true",
|
||||
for suffix, value := range map[string]string{
|
||||
"ACTOR_ID": "12",
|
||||
"TRIGGERING_ACTOR": "triggerer",
|
||||
"REPOSITORY_ID": "34",
|
||||
"REPOSITORY_OWNER_ID": "56",
|
||||
"WORKFLOW_REF": "owner/repo/.gitea/workflows/test.yml@refs/heads/main",
|
||||
"WORKFLOW_SHA": "workflow-sha",
|
||||
"REF_PROTECTED": "true",
|
||||
} {
|
||||
assert.Equal(t, value, env[name], name)
|
||||
assert.Equal(t, value, env["GITHUB_"+suffix], suffix)
|
||||
assert.Equal(t, value, env["GITEA_"+suffix], suffix)
|
||||
}
|
||||
ghc.RefProtected = false
|
||||
rc.withGithubEnv(t.Context(), ghc, env)
|
||||
@@ -922,12 +922,12 @@ func TestGetGitHubContext(t *testing.T) {
|
||||
github := rc.getGithubContext(t.Context())
|
||||
assert.Equal(t, testcase.serverURL, github.ServerURL)
|
||||
assert.Equal(t, testcase.apiURL, github.APIURL)
|
||||
env := map[string]string{}
|
||||
env := map[string]string{"GITEA_SERVER_URL": "stale", "GITEA_API_URL": "stale"}
|
||||
rc.withGithubEnv(t.Context(), github, env)
|
||||
_, exported := env["GITHUB_SERVER_URL"]
|
||||
assert.Equal(t, testcase.serverURL != "", exported)
|
||||
assert.Equal(t, testcase.serverURL, env["GITHUB_SERVER_URL"])
|
||||
assert.Equal(t, testcase.apiURL, env["GITHUB_API_URL"])
|
||||
assert.Equal(t, testcase.serverURL, env["GITEA_SERVER_URL"])
|
||||
assert.Equal(t, testcase.apiURL, env["GITEA_API_URL"])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,15 +157,7 @@ func runStepExecutor(step step, stage stepStage, executor common.Executor) commo
|
||||
stepSummaryIndex := topRC.CurrentStepIndex
|
||||
summaryFileCommand := path.Join("workflow", "step-summary-"+strconv.Itoa(stepSummaryIndex)+".md")
|
||||
(*step.getEnv())["GITHUB_STEP_SUMMARY"] = path.Join(actPath, summaryFileCommand)
|
||||
|
||||
{
|
||||
// For Gitea
|
||||
(*step.getEnv())["GITEA_OUTPUT"] = (*step.getEnv())["GITHUB_OUTPUT"]
|
||||
(*step.getEnv())["GITEA_STATE"] = (*step.getEnv())["GITHUB_STATE"]
|
||||
(*step.getEnv())["GITEA_PATH"] = (*step.getEnv())["GITHUB_PATH"]
|
||||
(*step.getEnv())["GITEA_ENV"] = (*step.getEnv())["GITHUB_ENV"]
|
||||
(*step.getEnv())["GITEA_STEP_SUMMARY"] = (*step.getEnv())["GITHUB_STEP_SUMMARY"]
|
||||
}
|
||||
aliasGiteaEnv(*step.getEnv())
|
||||
|
||||
// Reset the per-phase file-command files. GITHUB_STEP_SUMMARY is intentionally
|
||||
// excluded here and initialized below at most once per step so writes from later
|
||||
|
||||
@@ -58,7 +58,10 @@ func TestStepRun(t *testing.T) {
|
||||
},
|
||||
}
|
||||
sr.RunContext.ExprEval = sr.RunContext.NewExpressionEvaluator(t.Context())
|
||||
require.NoError(t, sr.Step.Env.Encode(map[string]string{"GITHUB_ACTION_REPOSITORY": "forged/repo", "GITHUB_ACTION_REF": "forged-ref"}))
|
||||
require.NoError(t, sr.Step.Env.Encode(map[string]string{
|
||||
"GITHUB_ACTION_REPOSITORY": "forged/repo", "GITHUB_ACTION_REF": "forged-ref",
|
||||
"GITEA_ACTION_REPOSITORY": "forged/repo", "GITEA_ACTION_REF": "forged-ref",
|
||||
}))
|
||||
|
||||
cm.On("Copy", "/var/run/act", []*container.FileEntry{fileEntry}).Return(noopExecutor)
|
||||
cm.On("Exec", []string{"bash", "--noprofile", "--norc", "-e", "-o", "pipefail", "/var/run/act/workflow/1.sh"}, mock.AnythingOfType("map[string]string"), "", "workdir").Return(noopExecutor)
|
||||
@@ -67,6 +70,9 @@ func TestStepRun(t *testing.T) {
|
||||
require.NoError(t, sr.main()(t.Context()))
|
||||
assert.Empty(t, sr.env["GITHUB_ACTION_REPOSITORY"])
|
||||
assert.Empty(t, sr.env["GITHUB_ACTION_REF"])
|
||||
assert.Empty(t, sr.env["GITEA_ACTION_REPOSITORY"])
|
||||
assert.Empty(t, sr.env["GITEA_ACTION_REF"])
|
||||
assert.Equal(t, sr.env["GITHUB_STEP_SUMMARY"], sr.env["GITEA_STEP_SUMMARY"])
|
||||
assert.Equal(t, "other/composite", sr.RunContext.Env["GITHUB_ACTION_REPOSITORY"])
|
||||
assert.Equal(t, "v1", sr.RunContext.Env["GITHUB_ACTION_REF"])
|
||||
|
||||
|
||||
@@ -155,18 +155,14 @@ func TestSetupEnv(t *testing.T) {
|
||||
require.NoError(t, setupEnv(t.Context(), testStep))
|
||||
require.NoError(t, setupInputs(t.Context(), testStep))
|
||||
|
||||
delete(env, "GITHUB_REF")
|
||||
delete(env, "GITHUB_REF_NAME")
|
||||
delete(env, "GITHUB_REF_TYPE")
|
||||
delete(env, "GITHUB_SHA")
|
||||
delete(env, "GITHUB_WORKSPACE")
|
||||
delete(env, "GITHUB_REPOSITORY")
|
||||
delete(env, "GITHUB_REPOSITORY_OWNER")
|
||||
delete(env, "GITHUB_ACTOR")
|
||||
for _, suffix := range []string{"REF", "REF_NAME", "REF_TYPE", "SHA", "WORKSPACE", "REPOSITORY", "REPOSITORY_OWNER", "ACTOR"} {
|
||||
delete(env, "GITHUB_"+suffix)
|
||||
delete(env, "GITEA_"+suffix)
|
||||
}
|
||||
delete(env, "RUNNER_NAME")
|
||||
delete(env, "RUNNER_WORKSPACE")
|
||||
|
||||
assert.Equal(t, map[string]string{
|
||||
expected := map[string]string{
|
||||
"ACT": "true",
|
||||
"ACT_SKIP_CHECKOUT": "true",
|
||||
"CI": "true",
|
||||
@@ -193,7 +189,13 @@ func TestSetupEnv(t *testing.T) {
|
||||
"RUNNER_ENVIRONMENT": "self-hosted",
|
||||
"RUNNER_PERFLOG": "/dev/null",
|
||||
"RUNNER_TRACKING_ID": "",
|
||||
}, env)
|
||||
}
|
||||
for name, value := range expected {
|
||||
if suffix, ok := strings.CutPrefix(name, "GITHUB_"); ok {
|
||||
expected["GITEA_"+suffix] = value
|
||||
}
|
||||
}
|
||||
assert.Equal(t, expected, env)
|
||||
|
||||
for _, expression := range []string{"inputs.args", "env.ARGS"} {
|
||||
t.Run("deferred inputs from "+expression, func(t *testing.T) {
|
||||
|
||||
@@ -45,7 +45,7 @@ A hook path that does not exist inside the job environment fails the job with `N
|
||||
|
||||
## Environment
|
||||
|
||||
A hook sees the job's environment: the workflow, job and `container:` `env:`, the runner's `envs`, and the `GITHUB_*` context variables, with the same masking applied to its output as to a step's. The step-specific ones (`GITHUB_ACTION`, `GITHUB_OUTPUT`, `GITHUB_STATE`) are not set — a hook is not a step, so `::save-state::` and `::set-output::` have nowhere to go.
|
||||
A hook sees the job's environment: the workflow, job and `container:` `env:`, the runner's `envs`, and the `GITHUB_*`/`GITEA_*` context variables, with the same masking applied to its output as to a step's. The step-specific ones (`GITHUB_ACTION`, `GITHUB_OUTPUT`, `GITHUB_STATE`) are not set — a hook is not a step, so `::save-state::` and `::set-output::` have nowhere to go.
|
||||
|
||||
Its stdout is part of the job log, after a collapsible group naming the hook and its shell, and is scanned for workflow commands. `::add-mask::` registers a value to be masked for the rest of the job. `::set-env::` and `::add-path::` apply to the steps that follow, but as in a step they need `ACTIONS_ALLOW_UNSECURE_COMMANDS: true`, and a refused one fails the hook.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user