From bbf9d7e90f3fee9e9968fc49c1ee6cfdb11f55e9 Mon Sep 17 00:00:00 2001 From: Akkuman Date: Thu, 28 Aug 2025 16:57:01 +0000 Subject: [PATCH 1/2] feat: support github mirror (#716) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref: https://github.com/go-gitea/gitea/issues/34858 when github_mirror='https://ghfast.top/https://github.com' it will clone from the github mirror However, there is an exception: because the cache is hashed using the string, if the same cache has been used before, it will still be pulled from github, only for the newly deployed act_ruuner In the following two scenarios, it will solve the problem encountered: 1. some github mirror is https://xxx.com/https://github.com/actions/checkout@v4, it will report error `Expected format {org}/{repo}[/path]@ref. Actual ‘https://xxx.com/https://github.com/actions/checkout@v4’ Input string was not in a correct format` 2. If I use an action that has a dependency on another action, even if I configure the url of the action I want to use, the action that the action introduces will still pull from github. for example https://github.com/rustic-beans/dagger-for-github/blob/02882cc2d9faf40e481120cfa4d754a5198c67f2/action.yml#L127-L132 Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/gitea/act_runner/pulls/716 Reviewed-by: Lunny Xiao Co-authored-by: Akkuman Co-committed-by: Akkuman --- internal/app/run/runner.go | 15 +++++++++++++-- internal/pkg/config/config.example.yaml | 5 +++++ internal/pkg/config/config.go | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/internal/app/run/runner.go b/internal/app/run/runner.go index a372d984..4b0f76b8 100644 --- a/internal/app/run/runner.go +++ b/internal/app/run/runner.go @@ -113,6 +113,17 @@ func (r *Runner) Run(ctx context.Context, task *runnerv1.Task) error { return nil } +// getDefaultActionsURL +// when DEFAULT_ACTIONS_URL == "https://github.com" and GithubMirror is not blank, +// it should be set to GithubMirror first. +func (r *Runner) getDefaultActionsURL(ctx context.Context, task *runnerv1.Task) string { + giteaDefaultActionsURL := task.Context.Fields["gitea_default_actions_url"].GetStringValue() + if giteaDefaultActionsURL == "https://github.com" && r.cfg.Runner.GithubMirror != "" { + return r.cfg.Runner.GithubMirror + } + return giteaDefaultActionsURL +} + func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.Reporter) (err error) { defer func() { if r := recover(); r != nil { @@ -137,7 +148,7 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report. taskContext := task.Context.Fields log.Infof("task %v repo is %v %v %v", task.Id, taskContext["repository"].GetStringValue(), - taskContext["gitea_default_actions_url"].GetStringValue(), + r.getDefaultActionsURL(ctx, task), r.client.Address()) preset := &model.GithubContext{ @@ -211,7 +222,7 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report. ContainerOptions: r.cfg.Container.Options, ContainerDaemonSocket: r.cfg.Container.DockerHost, Privileged: r.cfg.Container.Privileged, - DefaultActionInstance: taskContext["gitea_default_actions_url"].GetStringValue(), + DefaultActionInstance: r.getDefaultActionsURL(ctx, task), PlatformPicker: r.labels.PickPlatform, Vars: task.Vars, ValidVolumes: r.cfg.Container.ValidVolumes, diff --git a/internal/pkg/config/config.example.yaml b/internal/pkg/config/config.example.yaml index 2e3c3fb8..67b7db55 100644 --- a/internal/pkg/config/config.example.yaml +++ b/internal/pkg/config/config.example.yaml @@ -32,6 +32,11 @@ runner: fetch_timeout: 5s # The interval for fetching the job from the Gitea instance. fetch_interval: 2s + # The github_mirror of a runner is used to specify the mirror address of the github that pulls the action repository. + # It works when something like `uses: actions/checkout@v4` is used and DEFAULT_ACTIONS_URL is set to github, + # and github_mirror is not empty. In this case, + # it replaces https://github.com with the value here, which is useful for some special network environments. + github_mirror: '' # The labels of a runner are used to determine which jobs the runner can run, and how to run them. # Like: "macos-arm64:host" or "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest" # Find more images provided by Gitea at https://gitea.com/docker.gitea.com/runner-images . diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index afc34b9b..17147f07 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -31,6 +31,7 @@ type Runner struct { FetchTimeout time.Duration `yaml:"fetch_timeout"` // FetchTimeout specifies the timeout duration for fetching resources. FetchInterval time.Duration `yaml:"fetch_interval"` // FetchInterval specifies the interval duration for fetching resources. Labels []string `yaml:"labels"` // Labels specify the labels of the runner. Labels are declared on each startup + GithubMirror string `yaml:"github_mirror"` // GithubMirror defines what mirrors should be used when using github } // Cache represents the configuration for caching. From 8920c4a170603dc8f23e9e0d4ba0a9de13cd5f94 Mon Sep 17 00:00:00 2001 From: Christopher Homberger Date: Thu, 28 Aug 2025 17:28:08 +0000 Subject: [PATCH 2/2] Timeout to wait for and optionally require docker always (#741) * do not require docker cli in the runner image for waiting for a sidecar dockerd * allow to specify that `:host` labels would also only be accepted if docker is reachable Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/gitea/act_runner/pulls/741 Reviewed-by: Lunny Xiao Co-authored-by: Christopher Homberger Co-committed-by: Christopher Homberger --- internal/app/cmd/daemon.go | 31 ++++++++++++++++++++++++- internal/pkg/config/config.example.yaml | 4 ++++ internal/pkg/config/config.go | 20 +++++++++------- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/internal/app/cmd/daemon.go b/internal/app/cmd/daemon.go index d478dbbb..06810b2f 100644 --- a/internal/app/cmd/daemon.go +++ b/internal/app/cmd/daemon.go @@ -5,6 +5,7 @@ package cmd import ( "context" + "errors" "fmt" "os" "path" @@ -13,6 +14,7 @@ import ( "slices" "strconv" "strings" + "time" "connectrpc.com/connect" "github.com/mattn/go-isatty" @@ -64,7 +66,34 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu log.Warn("no labels configured, runner may not be able to pick up jobs") } - if ls.RequireDocker() { + if ls.RequireDocker() || cfg.Container.RequireDocker { + // Wait for dockerd be ready + if timeout := cfg.Container.DockerTimeout; timeout > 0 { + tctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + keepRunning := true + for keepRunning { + dockerSocketPath, err := getDockerSocketPath(cfg.Container.DockerHost) + if err != nil { + log.Errorf("Failed to get socket path: %s", err.Error()) + } else if err = envcheck.CheckIfDockerRunning(tctx, dockerSocketPath); errors.Is(err, context.Canceled) { + log.Infof("Docker wait timeout of %s expired", timeout.String()) + break + } else if err != nil { + log.Errorf("Docker connection failed: %s", err.Error()) + } else { + log.Infof("Docker is ready") + break + } + select { + case <-time.After(time.Second): + case <-tctx.Done(): + log.Infof("Docker wait timeout of %s expired", timeout.String()) + keepRunning = false + } + } + } + // Require dockerd be ready dockerSocketPath, err := getDockerSocketPath(cfg.Container.DockerHost) if err != nil { return err diff --git a/internal/pkg/config/config.example.yaml b/internal/pkg/config/config.example.yaml index 67b7db55..8fe4448d 100644 --- a/internal/pkg/config/config.example.yaml +++ b/internal/pkg/config/config.example.yaml @@ -99,6 +99,10 @@ container: force_pull: true # Rebuild docker image(s) even if already present force_rebuild: false + # Always require a reachable docker daemon, even if not required by act_runner + require_docker: false + # Timeout to wait for the docker daemon to be reachable, if docker is required by require_docker or act_runner + docker_timeout: 0s host: # The parent directory of a job's working directory. diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index 17147f07..93e82069 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -45,15 +45,17 @@ type Cache struct { // Container represents the configuration for the container. type Container struct { - Network string `yaml:"network"` // Network specifies the network for the container. - NetworkMode string `yaml:"network_mode"` // Deprecated: use Network instead. Could be removed after Gitea 1.20 - Privileged bool `yaml:"privileged"` // Privileged indicates whether the container runs in privileged mode. - Options string `yaml:"options"` // Options specifies additional options for the container. - WorkdirParent string `yaml:"workdir_parent"` // WorkdirParent specifies the parent directory for the container's working directory. - ValidVolumes []string `yaml:"valid_volumes"` // ValidVolumes specifies the volumes (including bind mounts) can be mounted to containers. - DockerHost string `yaml:"docker_host"` // DockerHost specifies the Docker host. It overrides the value specified in environment variable DOCKER_HOST. - ForcePull bool `yaml:"force_pull"` // Pull docker image(s) even if already present - ForceRebuild bool `yaml:"force_rebuild"` // Rebuild docker image(s) even if already present + Network string `yaml:"network"` // Network specifies the network for the container. + NetworkMode string `yaml:"network_mode"` // Deprecated: use Network instead. Could be removed after Gitea 1.20 + Privileged bool `yaml:"privileged"` // Privileged indicates whether the container runs in privileged mode. + Options string `yaml:"options"` // Options specifies additional options for the container. + WorkdirParent string `yaml:"workdir_parent"` // WorkdirParent specifies the parent directory for the container's working directory. + ValidVolumes []string `yaml:"valid_volumes"` // ValidVolumes specifies the volumes (including bind mounts) can be mounted to containers. + DockerHost string `yaml:"docker_host"` // DockerHost specifies the Docker host. It overrides the value specified in environment variable DOCKER_HOST. + ForcePull bool `yaml:"force_pull"` // Pull docker image(s) even if already present + ForceRebuild bool `yaml:"force_rebuild"` // Rebuild docker image(s) even if already present + RequireDocker bool `yaml:"require_docker"` // Always require a reachable docker daemon, even if not required by act_runner + DockerTimeout time.Duration `yaml:"docker_timeout"` // Timeout to wait for the docker daemon to be reachable, if docker is required by require_docker or act_runner } // Host represents the configuration for the host.