fix: align common behaviour with GitHub's runner (#1413)

Closes differences from GitHub's runner that common workflows hit:

- `ACTIONS_STEP_DEBUG` set as a repository variable enables debug output as on GitHub, where a secret of the same name still takes precedence. `runner.debug` and `RUNNER_DEBUG` are now also set inside composite actions, which lost the secret.
- `github.env` and `github.path` hold the file-command paths instead of being empty, so `echo "A=1" >> "${{ github.env }}"` works.
- Remote composite actions only get a pre stage when they nest actions. That stage evaluated `with:` before earlier steps ran, so an input like `${{ fromJSON(steps.meta.outputs.json).v }}` failed the job.
- `ports` on a job container are published, they were ignored while service ports worked.
- Dockerfile action build output reaches the job log. It was logged at debug and dropped, so a failing `RUN` showed only the final error.
- Local Docker actions honor their `.dockerignore`, as `docker build` does.
- Cancelling or timing out a host-mode step sends SIGINT, then SIGTERM after 7.5 seconds and SIGKILL after 2.5 more, as GitHub's runner does, so `trap` handlers and shutdown hooks run.
- `.sh` job hooks fall back to `sh` where bash is missing, and `.ps1` hooks to `powershell` where pwsh is missing, as on GitHub.

_Written by Claude (Opus 5.5)._

Reviewed-on: https://gitea.com/gitea/runner/pulls/1413
Reviewed-by: bircni <[email protected]>
Co-authored-by: silverwind <[email protected]>
This commit is contained in:
silverwind authored and bircni committed 2026-11-12 15:28:47 +00:00
1 parent 0dfec377d2
commit 645b17de72
25 files changed
+340 -91

No files matched your search

+33
View File
@@ -6,9 +6,11 @@
package process
import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
"testing"
@@ -95,3 +97,34 @@ func TestTreeKillCancelBeforeCaptureKillsTree(t *testing.T) {
require.Error(t, cmd.Wait())
require.Eventually(t, func() bool { return !processAlive(childPID) }, 5*time.Second, 10*time.Millisecond)
}
func TestTreeKillCancelRunsInterruptTrap(t *testing.T) {
ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second)
defer cancel()
marker := filepath.Join(t.TempDir(), "interrupted")
cmd := exec.CommandContext(ctx, "/bin/sh", "-c", `trap 'echo interrupted > "$1"; exit 0' INT; echo ready; read value`, "sh", marker)
cmd.SysProcAttr = SysProcAttr("", false)
input, err := cmd.StdinPipe()
require.NoError(t, err)
defer input.Close()
output, err := cmd.StdoutPipe()
require.NoError(t, err)
treeKill := NewTreeKill(cmd)
treeKill.GracefulCancel = true
require.NoError(t, cmd.Start())
killer, err := treeKill.Capture(cmd.Process)
require.NoError(t, err)
defer killer.Close()
t.Cleanup(func() {
_ = killer.Kill()
_ = cmd.Wait()
})
var ready string
_, err = fmt.Fscanln(output, &ready)
require.NoError(t, err)
require.Equal(t, "ready", ready)
cancel()
require.ErrorIs(t, treeKill.Wait(ctx, cmd), context.Canceled)
require.FileExists(t, marker)
}