From e100e3084c4bb5b0c1851b82d9490d69a94e55a6 Mon Sep 17 00:00:00 2001 From: earl-warren Date: Thu, 7 Aug 2025 21:03:44 +0000 Subject: [PATCH] feat: log parsed commands and step summary (#824) Refs https://github.com/nektos/act/pull/2761 --- * feat: log parsed command data in json logger * Could be used to upload the GITHUB_STEP_SUMMARY by downstream Projects * You can see the summary and other commands * Access the raw line of most commands * Update step.go * Update step.go * Update push.yml * . --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> (cherry picked from commit bb7db7b1c8a456d46907f3e65a6c4c2c1dcb6286) ``` Conflicts: act/runner/command.go act/runner/runner_test.go trivial context conflicts for both ``` - features - [PR](https://code.forgejo.org/forgejo/runner/pulls/824): feat: log parsed commands and step summary Co-authored-by: ChristopherHX Reviewed-on: https://code.forgejo.org/forgejo/runner/pulls/824 Reviewed-by: Gusted --- act/runner/command.go | 29 ++++++------ act/runner/runner_test.go | 1 + act/runner/step.go | 59 +++++++++++++++--------- act/runner/step_action_local_test.go | 2 + act/runner/step_action_remote_test.go | 6 ++- act/runner/step_docker_test.go | 1 + act/runner/step_run_test.go | 1 + act/runner/testdata/stepsummary/push.yml | 27 +++++++++++ 8 files changed, 90 insertions(+), 36 deletions(-) create mode 100644 act/runner/testdata/stepsummary/push.yml diff --git a/act/runner/command.go b/act/runner/command.go index 98942322..654a0e4c 100644 --- a/act/runner/command.go +++ b/act/runner/command.go @@ -6,6 +6,8 @@ import ( "strings" "code.forgejo.org/forgejo/runner/v9/act/common" + + "github.com/sirupsen/logrus" ) var ( @@ -43,11 +45,12 @@ func (rc *RunContext) commandHandler(ctx context.Context) common.LineHandler { } if resumeCommand != "" && command != resumeCommand { - logger.Infof(" \U00002699 %s", line) + logger.WithFields(logrus.Fields{"command": "ignored", "raw": line}).Infof(" \U00002699 %s", line) return false } arg = unescapeCommandData(arg) kvPairs = unescapeKvPairs(kvPairs) + defCommandLogger := logger.WithFields(logrus.Fields{"command": command, "kvPairs": kvPairs, "arg": arg, "raw": line}) switch command { case "set-env": rc.setEnv(ctx, kvPairs, arg) @@ -56,27 +59,27 @@ func (rc *RunContext) commandHandler(ctx context.Context) common.LineHandler { case "add-path": rc.addPath(ctx, arg) case "debug": - logger.Infof(" \U0001F4AC %s", line) + defCommandLogger.Debugf(" \U0001F4AC %s", line) case "warning": - logger.Infof(" \U0001F6A7 %s", line) + defCommandLogger.Warnf(" \U0001F6A7 %s", line) case "error": - logger.Infof(" \U00002757 %s", line) + defCommandLogger.Errorf(" \U00002757 %s", line) case "add-mask": rc.AddMask(arg) - logger.Infof(" \U00002699 %s", "***") + defCommandLogger.Infof(" \U00002699 %s", "***") case "stop-commands": resumeCommand = arg - logger.Infof(" \U00002699 %s", line) + defCommandLogger.Infof(" \U00002699 %s", line) case resumeCommand: resumeCommand = "" - logger.Infof(" \U00002699 %s", line) + defCommandLogger.Infof(" \U00002699 %s", line) case "save-state": - logger.Infof(" \U0001f4be %s", line) + defCommandLogger.Infof(" \U0001f4be %s", line) rc.saveState(ctx, kvPairs, arg) case "add-matcher": - logger.Infof(" \U00002753 add-matcher %s", arg) + defCommandLogger.Infof(" \U00002753 add-matcher %s", arg) default: - logger.Infof(" \U00002753 %s", line) + defCommandLogger.Infof(" \U00002753 %s", line) } // return true to let gitea's logger handle these special outputs also @@ -86,7 +89,7 @@ func (rc *RunContext) commandHandler(ctx context.Context) common.LineHandler { func (rc *RunContext) setEnv(ctx context.Context, kvPairs map[string]string, arg string) { name := kvPairs["name"] - common.Logger(ctx).Infof(" \U00002699 ::set-env:: %s=%s", name, arg) + common.Logger(ctx).WithFields(logrus.Fields{"command": "set-env", "name": name, "arg": arg}).Infof(" \U00002699 ::set-env:: %s=%s", name, arg) if rc.Env == nil { rc.Env = make(map[string]string) } @@ -119,12 +122,12 @@ func (rc *RunContext) setOutput(ctx context.Context, kvPairs map[string]string, return } - logger.Infof(" \U00002699 ::set-output:: %s=%s", outputName, arg) + logger.WithFields(logrus.Fields{"command": "set-output", "name": outputName, "arg": arg}).Infof(" \U00002699 ::set-output:: %s=%s", outputName, arg) result.Outputs[outputName] = arg } func (rc *RunContext) addPath(ctx context.Context, arg string) { - common.Logger(ctx).Infof(" \U00002699 ::add-path:: %s", arg) + common.Logger(ctx).WithFields(logrus.Fields{"command": "add-path", "arg": arg}).Infof(" \U00002699 ::add-path:: %s", arg) extraPath := []string{arg} for _, v := range rc.ExtraPath { if v != arg { diff --git a/act/runner/runner_test.go b/act/runner/runner_test.go index d7a5b876..be3dd501 100644 --- a/act/runner/runner_test.go +++ b/act/runner/runner_test.go @@ -317,6 +317,7 @@ func TestRunner_RunEvent(t *testing.T) { {workdir, "set-env-step-env-override", "push", "", platforms, secrets}, {workdir, "set-env-new-env-file-per-step", "push", "", platforms, secrets}, {workdir, "no-panic-on-invalid-composite-action", "push", "missing steps in composite action", platforms, secrets}, + {workdir, "stepsummary", "push", "", platforms, secrets}, {workdir, "tool-cache", "push", "", platforms, secrets}, // services diff --git a/act/runner/step.go b/act/runner/step.go index 72102e8c..0d2de3fd 100644 --- a/act/runner/step.go +++ b/act/runner/step.go @@ -1,8 +1,11 @@ package runner import ( + "archive/tar" "context" + "errors" "fmt" + "io" "path" "strconv" "strings" @@ -12,6 +15,8 @@ import ( "code.forgejo.org/forgejo/runner/v9/act/container" "code.forgejo.org/forgejo/runner/v9/act/exprparser" "code.forgejo.org/forgejo/runner/v9/act/model" + + "github.com/sirupsen/logrus" ) type step interface { @@ -49,6 +54,32 @@ func (s stepStage) String() string { return "Unknown" } +func processRunnerSummaryCommand(ctx context.Context, fileName string, rc *RunContext) error { + if common.Dryrun(ctx) { + return nil + } + pathTar, err := rc.JobContainer.GetContainerArchive(ctx, path.Join(rc.JobContainer.GetActPath(), fileName)) + if err != nil { + return err + } + defer pathTar.Close() + + reader := tar.NewReader(pathTar) + _, err = reader.Next() + if err != nil && err != io.EOF { + return err + } + summary, err := io.ReadAll(reader) + if err != nil { + return err + } + if len(summary) == 0 { + return nil + } + common.Logger(ctx).WithFields(logrus.Fields{"command": "summary", "content": string(summary)}).Infof(" \U00002699 Summary - %s", string(summary)) + return nil +} + func processRunnerEnvFileCommand(ctx context.Context, fileName string, rc *RunContext, setter func(context.Context, map[string]string, string)) error { env := map[string]string{} err := rc.JobContainer.UpdateFromEnv(path.Join(rc.JobContainer.GetActPath(), fileName), &env)(ctx) @@ -171,27 +202,13 @@ func runStepExecutor(step step, stage stepStage, executor common.Executor) commo logger.WithField("stepResult", stepResult.Outcome).Errorf(" \u274C Failure - %s %s", stage, stepString) } // Process Runner File Commands - orgerr := err - err = processRunnerEnvFileCommand(ctx, envFileCommand, rc, rc.setEnv) - if err != nil { - return err - } - err = processRunnerEnvFileCommand(ctx, stateFileCommand, rc, rc.saveState) - if err != nil { - return err - } - err = processRunnerEnvFileCommand(ctx, outputFileCommand, rc, rc.setOutput) - if err != nil { - return err - } - err = rc.UpdateExtraPath(ctx, path.Join(actPath, pathFileCommand)) - if err != nil { - return err - } - if orgerr != nil { - return orgerr - } - return err + ferrors := []error{err} + ferrors = append(ferrors, processRunnerEnvFileCommand(ctx, envFileCommand, rc, rc.setEnv)) + ferrors = append(ferrors, processRunnerEnvFileCommand(ctx, stateFileCommand, rc, rc.saveState)) + ferrors = append(ferrors, processRunnerEnvFileCommand(ctx, outputFileCommand, rc, rc.setOutput)) + ferrors = append(ferrors, processRunnerSummaryCommand(ctx, summaryFileCommand, rc)) + ferrors = append(ferrors, rc.UpdateExtraPath(ctx, path.Join(actPath, pathFileCommand))) + return errors.Join(ferrors...) } } diff --git a/act/runner/step_action_local_test.go b/act/runner/step_action_local_test.go index c988d3b1..3af17d96 100644 --- a/act/runner/step_action_local_test.go +++ b/act/runner/step_action_local_test.go @@ -85,6 +85,7 @@ func TestStepActionLocalTest(t *testing.T) { return nil }) + cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/SUMMARY.md").Return(io.NopCloser(&bytes.Buffer{}), nil) cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/pathcmd.txt").Return(io.NopCloser(&bytes.Buffer{}), nil) salm.On("runAction", sal, filepath.Clean("/tmp/path/to/action"), (*remoteAction)(nil)).Return(func(ctx context.Context) error { @@ -280,6 +281,7 @@ func TestStepActionLocalPost(t *testing.T) { return nil }) + cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/SUMMARY.md").Return(io.NopCloser(&bytes.Buffer{}), nil) cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/pathcmd.txt").Return(io.NopCloser(&bytes.Buffer{}), nil) } diff --git a/act/runner/step_action_remote_test.go b/act/runner/step_action_remote_test.go index 864a580e..630c84b2 100644 --- a/act/runner/step_action_remote_test.go +++ b/act/runner/step_action_remote_test.go @@ -180,6 +180,7 @@ func TestStepActionRemoteOK(t *testing.T) { return nil }) + cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/SUMMARY.md").Return(io.NopCloser(&bytes.Buffer{}), nil) cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/pathcmd.txt").Return(io.NopCloser(&bytes.Buffer{}), nil) } @@ -188,9 +189,9 @@ func TestStepActionRemoteOK(t *testing.T) { err = sar.main()(ctx) } - assert.Equal(t, tt.runError, err) + assert.ErrorIs(t, err, tt.runError) assert.Equal(t, tt.mocks.cloned, clonedAction) - assert.Equal(t, tt.result, sar.RunContext.StepResults["step"]) + assert.Equal(t, sar.RunContext.StepResults["step"], tt.result) sarm.AssertExpectations(t) cm.AssertExpectations(t) @@ -508,6 +509,7 @@ func TestStepActionRemotePost(t *testing.T) { return nil }) + cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/SUMMARY.md").Return(io.NopCloser(&bytes.Buffer{}), nil) cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/pathcmd.txt").Return(io.NopCloser(&bytes.Buffer{}), nil) } diff --git a/act/runner/step_docker_test.go b/act/runner/step_docker_test.go index 9608978e..6b6c11db 100644 --- a/act/runner/step_docker_test.go +++ b/act/runner/step_docker_test.go @@ -93,6 +93,7 @@ func TestStepDockerMain(t *testing.T) { return nil }) + cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/SUMMARY.md").Return(io.NopCloser(&bytes.Buffer{}), nil) cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/pathcmd.txt").Return(io.NopCloser(&bytes.Buffer{}), nil) err := sd.main()(ctx) diff --git a/act/runner/step_run_test.go b/act/runner/step_run_test.go index 611b1274..10e8bd19 100644 --- a/act/runner/step_run_test.go +++ b/act/runner/step_run_test.go @@ -74,6 +74,7 @@ func TestStepRun(t *testing.T) { ctx := context.Background() + cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/SUMMARY.md").Return(io.NopCloser(&bytes.Buffer{}), nil) cm.On("GetContainerArchive", ctx, "/var/run/act/workflow/pathcmd.txt").Return(io.NopCloser(&bytes.Buffer{}), nil) err := sr.main()(ctx) diff --git a/act/runner/testdata/stepsummary/push.yml b/act/runner/testdata/stepsummary/push.yml new file mode 100644 index 00000000..cb6c8e75 --- /dev/null +++ b/act/runner/testdata/stepsummary/push.yml @@ -0,0 +1,27 @@ +name: Step Summary Example + +on: [push] + +jobs: + create_summary: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: https://data.forgejo.org/actions/checkout@v4 + + # GITHUB_STEP_SUMMARY test + - name: Create Step Summary + uses: https://github.com/actions/github-script@v7 + with: + script: | + const summary = ` + ## Workflow Summary + - **Repository**: ${context.repo.owner}/${context.repo.repo} + - **Branch**: ${context.ref} + - **Commit SHA**: ${context.sha} + - **Event**: ${context.eventName} + `; + console.log('Summary:', summary); + await core.summary.addRaw(summary); + await core.summary.write(); + github-token: none