diff --git a/.golangci.yml b/.golangci.yml index 8505828..41f9683 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,14 +1,11 @@ linters: enable: - gosimple - - deadcode - typecheck - govet - errcheck - staticcheck - unused - - structcheck - - varcheck - dupl #- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time. - gofmt @@ -112,7 +109,6 @@ issues: - gocritic - linters: - unused - - deadcode text: "swagger" - path: contrib/pr/checkout.go linters: @@ -154,9 +150,6 @@ issues: - path: cmd/dump.go linters: - dupl - - path: services/webhook/webhook.go - linters: - - structcheck - text: "commentFormatting: put a space between `//` and comment text" linters: - gocritic diff --git a/Dockerfile b/Dockerfile index 478938f..175d32d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.20-alpine3.18 as builder +FROM golang:1.20.5-alpine3.18 as builder # Do not remove `git` here, it is required for getting runner version when executing `make build` RUN apk add --no-cache make git diff --git a/Dockerfile.rootless b/Dockerfile.rootless index b80033d..2fb40d9 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,4 +1,4 @@ -FROM golang:1.20-alpine3.18 as builder +FROM golang:1.20.5-alpine3.18 as builder # Do not remove `git` here, it is required for getting runner version when executing `make build` RUN apk add --no-cache make git diff --git a/README.md b/README.md index f031dca..4810b28 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,13 @@ make docker ## Quickstart +Actions are disabled by default, so you need to add the following to the configuration file of your Gitea instance to enable it: + +```ini +[actions] +ENABLED=true +``` + ### Register ```bash @@ -36,7 +43,7 @@ And you will be asked to input: 1. Gitea instance URL, like `http://192.168.8.8:3000/`. You should use your gitea instance ROOT_URL as the instance argument and you should not use `localhost` or `127.0.0.1` as instance IP; -2. Runner token, you can get it from `http://192.168.8.8:3000/admin/runners`; +2. Runner token, you can get it from `http://192.168.8.8:3000/admin/actions/runners`; 3. Runner name, you can just leave it blank; 4. Runner labels, you can just leave it blank. @@ -72,6 +79,12 @@ If the registry succeed, it will run immediately. Next time, you could run the r ./act_runner daemon ``` +### Run with docker + +```bash +docker run -e GITEA_INSTANCE_URL=https://your_gitea.com -e GITEA_RUNNER_REGISTRATION_TOKEN= -v /var/run/docker.sock:/var/run/docker.sock --name my_runner gitea/act_runner:nightly +``` + ### Configuration You can also configure the runner with a configuration file. diff --git a/go.mod b/go.mod index ac1aec4..881faf2 100644 --- a/go.mod +++ b/go.mod @@ -89,4 +89,4 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect ) -replace github.com/nektos/act => gitea.com/gitea/act v0.246.1-0.20230620073610-515c2c429d6d +replace github.com/nektos/act => gitea.com/gitea/act v0.246.2-0.20230717034634-cdc6d4bc6a38 diff --git a/go.sum b/go.sum index 3d3b3b9..6b82b6a 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ code.gitea.io/actions-proto-go v0.3.1 h1:PMyiQtBKb8dNnpEO2R5rcZdXSis+UQZVo/SciMt code.gitea.io/actions-proto-go v0.3.1/go.mod h1:00ys5QDo1iHN1tHNvvddAcy2W/g+425hQya1cCSvq9A= code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5 h1:daBEK2GQeqGikJESctP5Cu1i33z5ztAD4kyQWiw185M= code.gitea.io/gitea-vet v0.2.3-0.20230113022436-2b1561217fa5/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= -gitea.com/gitea/act v0.246.1-0.20230620073610-515c2c429d6d h1:msAht+dSo+RLcKox3imOiMWUEAID386ffpG+SMrQdbY= -gitea.com/gitea/act v0.246.1-0.20230620073610-515c2c429d6d/go.mod h1:oU/5klyP5O+J2psPS3t50t09+SNVg+fZ/jN4lDZAq1U= +gitea.com/gitea/act v0.246.2-0.20230717034634-cdc6d4bc6a38 h1:whUEO/qPkYfpbL1he9TuIIzz2P4v6xEwb2lT6E/4F7A= +gitea.com/gitea/act v0.246.2-0.20230717034634-cdc6d4bc6a38/go.mod h1:oU/5klyP5O+J2psPS3t50t09+SNVg+fZ/jN4lDZAq1U= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= diff --git a/internal/app/cmd/cache-server.go b/internal/app/cmd/cache-server.go new file mode 100644 index 0000000..21b3352 --- /dev/null +++ b/internal/app/cmd/cache-server.go @@ -0,0 +1,69 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cmd + +import ( + "context" + "fmt" + "os" + "os/signal" + + "gitea.com/gitea/act_runner/internal/pkg/config" + + "github.com/nektos/act/pkg/artifactcache" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +type cacheServerArgs struct { + Dir string + Host string + Port uint16 +} + +func runCacheServer(ctx context.Context, configFile *string, cacheArgs *cacheServerArgs) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + cfg, err := config.LoadDefault(*configFile) + if err != nil { + return fmt.Errorf("invalid configuration: %w", err) + } + + initLogging(cfg) + + var ( + dir = cfg.Cache.Dir + host = cfg.Cache.Host + port = cfg.Cache.Port + ) + + // cacheArgs has higher priority + if cacheArgs.Dir != "" { + dir = cacheArgs.Dir + } + if cacheArgs.Host != "" { + host = cacheArgs.Host + } + if cacheArgs.Port != 0 { + port = cacheArgs.Port + } + + cacheHandler, err := artifactcache.StartHandler( + dir, + host, + port, + log.StandardLogger().WithField("module", "cache_request"), + ) + if err != nil { + return err + } + + log.Infof("cache server is listening on %v", cacheHandler.ExternalURL()) + + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + <-c + + return nil + } +} diff --git a/internal/app/cmd/cmd.go b/internal/app/cmd/cmd.go index f6d2bda..254e2f0 100644 --- a/internal/app/cmd/cmd.go +++ b/internal/app/cmd/cmd.go @@ -63,6 +63,19 @@ func Execute(ctx context.Context) { }, }) + // ./act_runner cache-server + var cacheArgs cacheServerArgs + cacheCmd := &cobra.Command{ + Use: "cache-server", + Short: "Start a cache server for the cache action", + Args: cobra.MaximumNArgs(0), + RunE: runCacheServer(ctx, &configFile, &cacheArgs), + } + cacheCmd.Flags().StringVarP(&cacheArgs.Dir, "dir", "d", "", "Cache directory") + cacheCmd.Flags().StringVarP(&cacheArgs.Host, "host", "s", "", "Host of the cache server") + cacheCmd.Flags().Uint16VarP(&cacheArgs.Port, "port", "p", 0, "Port of the cache server") + rootCmd.AddCommand(cacheCmd) + // hide completion command rootCmd.CompletionOptions.HiddenDefaultCmd = true diff --git a/internal/app/cmd/daemon.go b/internal/app/cmd/daemon.go index 05c80a2..ec02e08 100644 --- a/internal/app/cmd/daemon.go +++ b/internal/app/cmd/daemon.go @@ -8,6 +8,7 @@ import ( "fmt" "os" "path" + "path/filepath" "runtime" "strconv" "strings" @@ -78,7 +79,7 @@ func runDaemon(ctx context.Context, configFile *string) func(cmd *cobra.Command, cfg.Container.DockerHost = dockerSocketPath } // check the scheme, if the scheme is not npipe or unix - // set cfg.Container.DockerHost to "-" because it can't be mounted to the job conatiner + // set cfg.Container.DockerHost to "-" because it can't be mounted to the job container if protoIndex := strings.Index(cfg.Container.DockerHost, "://"); protoIndex != -1 { scheme := cfg.Container.DockerHost[:protoIndex] if !strings.EqualFold(scheme, "npipe") && !strings.EqualFold(scheme, "unix") { @@ -160,6 +161,15 @@ func initLogging(cfg *config.Config) { } } +var commonSocketPaths = []string{ + "/var/run/docker.sock", + "/var/run/podman/podman.sock", + "$HOME/.colima/docker.sock", + "$XDG_RUNTIME_DIR/docker.sock", + `\\.\pipe\docker_engine`, + "$HOME/.docker/run/docker.sock", +} + func getDockerSocketPath(configDockerHost string) (string, error) { // a `-` means don't mount the docker socket to job containers if configDockerHost != "" && configDockerHost != "-" { @@ -171,5 +181,14 @@ func getDockerSocketPath(configDockerHost string) (string, error) { return socket, nil } + for _, p := range commonSocketPaths { + if _, err := os.Lstat(os.ExpandEnv(p)); err == nil { + if strings.HasPrefix(p, `\\.\`) { + return "npipe://" + filepath.ToSlash(os.ExpandEnv(p)), nil + } + return "unix://" + filepath.ToSlash(os.ExpandEnv(p)), nil + } + } + return "", fmt.Errorf("daemon Docker Engine socket not found and docker_host config was invalid") } diff --git a/internal/app/cmd/exec.go b/internal/app/cmd/exec.go index 97b6752..9a28170 100644 --- a/internal/app/cmd/exec.go +++ b/internal/app/cmd/exec.go @@ -39,7 +39,7 @@ type executeArgs struct { envs []string envfile string secrets []string - defaultActionsUrls []string + defaultActionsURL string insecureSecrets bool privileged bool usernsMode string @@ -252,7 +252,7 @@ func runExecList(ctx context.Context, planner model.WorkflowPlanner, execArgs *e var filterPlan *model.Plan // Determine the event name to be filtered - var filterEventName string = "" + var filterEventName string if len(execArgs.event) > 0 { log.Infof("Using chosed event for filtering: %s", execArgs.event) @@ -289,7 +289,7 @@ func runExecList(ctx context.Context, planner model.WorkflowPlanner, execArgs *e } } - printList(filterPlan) + _ = printList(filterPlan) return nil } @@ -359,11 +359,11 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command execArgs.cacheHandler = handler if len(execArgs.artifactServerAddr) == 0 { - if ip := common.GetOutboundIP(); ip == nil { + ip := common.GetOutboundIP() + if ip == nil { return fmt.Errorf("unable to determine outbound IP address") - } else { - execArgs.artifactServerAddr = ip.String() } + execArgs.artifactServerAddr = ip.String() } if len(execArgs.artifactServerPath) == 0 { @@ -404,10 +404,10 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command NoSkipCheckout: execArgs.noSkipCheckout, // PresetGitHubContext: preset, // EventJSON: string(eventJSON), - ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%s", eventName), - ContainerMaxLifetime: maxLifetime, - ContainerNetworkMode: container.NetworkMode(execArgs.network), - DefaultActionsURLs: execArgs.defaultActionsUrls, + ContainerNamePrefix: fmt.Sprintf("GITEA-ACTIONS-TASK-%s", eventName), + ContainerMaxLifetime: maxLifetime, + ContainerNetworkMode: container.NetworkMode(execArgs.network), + DefaultActionInstance: execArgs.defaultActionsURL, PlatformPicker: func(_ []string) string { return execArgs.image }, @@ -423,7 +423,7 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command } if !execArgs.debug { - logLevel := log.Level(log.InfoLevel) + logLevel := log.InfoLevel config.JobLoggerLevel = &logLevel } @@ -480,7 +480,7 @@ func loadExecCmd(ctx context.Context) *cobra.Command { execCmd.PersistentFlags().StringVarP(&execArg.artifactServerPath, "artifact-server-path", "", ".", "Defines the path where the artifact server stores uploads and retrieves downloads from. If not specified the artifact server will not start.") execCmd.PersistentFlags().StringVarP(&execArg.artifactServerAddr, "artifact-server-addr", "", "", "Defines the address where the artifact server listens") execCmd.PersistentFlags().StringVarP(&execArg.artifactServerPort, "artifact-server-port", "", "34567", "Defines the port where the artifact server listens (will only bind to localhost).") - execCmd.PersistentFlags().StringArrayVarP(&execArg.defaultActionsUrls, "default-actions-url", "", []string{"https://gitea.com", "https://github.com"}, "Defines the default url list of action instance.") + execCmd.PersistentFlags().StringVarP(&execArg.defaultActionsURL, "default-actions-url", "", "https://github.com", "Defines the default url of action instance.") execCmd.PersistentFlags().BoolVarP(&execArg.noSkipCheckout, "no-skip-checkout", "", false, "Do not skip actions/checkout") execCmd.PersistentFlags().BoolVarP(&execArg.debug, "debug", "d", false, "enable debug log") execCmd.PersistentFlags().BoolVarP(&execArg.dryrun, "dryrun", "n", false, "dryrun mode") diff --git a/internal/app/cmd/register.go b/internal/app/cmd/register.go index fcea74d..f1114cf 100644 --- a/internal/app/cmd/register.go +++ b/internal/app/cmd/register.go @@ -47,12 +47,12 @@ func runRegister(ctx context.Context, regArgs *registerArgs, configFile *string) } if regArgs.NoInteractive { - if err := registerNoInteractive(*configFile, regArgs); err != nil { + if err := registerNoInteractive(ctx, *configFile, regArgs); err != nil { return err } } else { go func() { - if err := registerInteractive(*configFile); err != nil { + if err := registerInteractive(ctx, *configFile); err != nil { log.Fatal(err) return } @@ -187,7 +187,7 @@ func (r *registerInputs) assignToNext(stage registerStage, value string, cfg *co return StageUnknown } -func registerInteractive(configFile string) error { +func registerInteractive(ctx context.Context, configFile string) error { var ( reader = bufio.NewReader(os.Stdin) stage = StageInputInstance @@ -213,11 +213,10 @@ func registerInteractive(configFile string) error { if stage == StageWaitingForRegistration { log.Infof("Registering runner, name=%s, instance=%s, labels=%v.", inputs.RunnerName, inputs.InstanceAddr, inputs.Labels) - if err := doRegister(cfg, inputs); err != nil { + if err := doRegister(ctx, cfg, inputs); err != nil { return fmt.Errorf("Failed to register runner: %w", err) - } else { - log.Infof("Runner registered successfully.") } + log.Infof("Runner registered successfully.") return nil } @@ -250,7 +249,7 @@ func printStageHelp(stage registerStage) { } } -func registerNoInteractive(configFile string, regArgs *registerArgs) error { +func registerNoInteractive(ctx context.Context, configFile string, regArgs *registerArgs) error { cfg, err := config.LoadDefault(configFile) if err != nil { return err @@ -282,16 +281,14 @@ func registerNoInteractive(configFile string, regArgs *registerArgs) error { log.WithError(err).Errorf("Invalid input, please re-run act command.") return nil } - if err := doRegister(cfg, inputs); err != nil { + if err := doRegister(ctx, cfg, inputs); err != nil { return fmt.Errorf("Failed to register runner: %w", err) } log.Infof("Runner registered successfully.") return nil } -func doRegister(cfg *config.Config, inputs *registerInputs) error { - ctx := context.Background() - +func doRegister(ctx context.Context, cfg *config.Config, inputs *registerInputs) error { // initial http client cli := client.New( inputs.InstanceAddr, @@ -307,7 +304,7 @@ func doRegister(cfg *config.Config, inputs *registerInputs) error { })) select { case <-ctx.Done(): - return nil + return ctx.Err() default: } if ctx.Err() != nil { diff --git a/internal/app/poll/poller.go b/internal/app/poll/poller.go index 148af29..065a7b9 100644 --- a/internal/app/poll/poller.go +++ b/internal/app/poll/poller.go @@ -6,6 +6,7 @@ package poll import ( "context" "errors" + "fmt" "sync" runnerv1 "code.gitea.io/actions-proto-go/runner/v1" @@ -48,19 +49,30 @@ func (p *Poller) Poll(ctx context.Context) { func (p *Poller) poll(ctx context.Context, wg *sync.WaitGroup, limiter *rate.Limiter) { defer wg.Done() for { - if err := limiter.Wait(ctx); err != nil { - if ctx.Err() != nil { - log.WithError(err).Debug("limiter wait failed") - } - return + p.pollTaskWithRateLimit(ctx, limiter) + } +} + +func (p *Poller) pollTaskWithRateLimit(ctx context.Context, limiter *rate.Limiter) { + defer func() { + if r := recover(); r != nil { + err := fmt.Errorf("panic: %v", r) + log.WithError(err).Error("panic in pollTaskWithRateLimit") } - task, ok := p.fetchTask(ctx) - if !ok { - continue - } - if err := p.runner.Run(ctx, task); err != nil { - log.WithError(err).Error("failed to run task") + }() + + if err := limiter.Wait(ctx); err != nil { + if ctx.Err() != nil { + log.WithError(err).Debug("limiter wait failed") } + return + } + task, ok := p.fetchTask(ctx) + if !ok { + return + } + if err := p.runner.Run(ctx, task); err != nil { + log.WithError(err).Error("failed to run task") } } diff --git a/internal/app/run/runner.go b/internal/app/run/runner.go index 2f40a05..c9f5f3e 100644 --- a/internal/app/run/runner.go +++ b/internal/app/run/runner.go @@ -53,17 +53,21 @@ func NewRunner(cfg *config.Config, reg *config.Registration, cli client.Client) envs[k] = v } if cfg.Cache.Enabled == nil || *cfg.Cache.Enabled { - cacheHandler, err := artifactcache.StartHandler( - cfg.Cache.Dir, - cfg.Cache.Host, - cfg.Cache.Port, - log.StandardLogger().WithField("module", "cache_request"), - ) - if err != nil { - log.Errorf("cannot init cache server, it will be disabled: %v", err) - // go on + if cfg.Cache.ExternalServer != "" { + envs["ACTIONS_CACHE_URL"] = cfg.Cache.ExternalServer } else { - envs["ACTIONS_CACHE_URL"] = cacheHandler.ExternalURL() + "/" + cacheHandler, err := artifactcache.StartHandler( + cfg.Cache.Dir, + cfg.Cache.Host, + cfg.Cache.Port, + log.StandardLogger().WithField("module", "cache_request"), + ) + if err != nil { + log.Errorf("cannot init cache server, it will be disabled: %v", err) + // go on + } else { + envs["ACTIONS_CACHE_URL"] = cacheHandler.ExternalURL() + "/" + } } } @@ -87,10 +91,9 @@ func NewRunner(cfg *config.Config, reg *config.Registration, cli client.Client) func (r *Runner) Run(ctx context.Context, task *runnerv1.Task) error { if _, ok := r.runningTasks.Load(task.Id); ok { return fmt.Errorf("task %d is already running", task.Id) - } else { - r.runningTasks.Store(task.Id, struct{}{}) - defer r.runningTasks.Delete(task.Id) } + r.runningTasks.Store(task.Id, struct{}{}) + defer r.runningTasks.Delete(task.Id) ctx, cancel := context.WithTimeout(ctx, r.cfg.Runner.Timeout) defer cancel() @@ -197,7 +200,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, - DefaultActionsURLs: parseDefaultActionsURLs(taskContext["gitea_default_actions_url"].GetStringValue()), + DefaultActionInstance: taskContext["gitea_default_actions_url"].GetStringValue(), PlatformPicker: r.labels.PickPlatform, Vars: task.Vars, ValidVolumes: r.cfg.Container.ValidVolumes, @@ -219,16 +222,6 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report. return execErr } -func parseDefaultActionsURLs(s string) []string { - urls := strings.Split(s, ",") - trimmed := make([]string, 0, len(urls)) - for _, u := range urls { - t := strings.TrimRight(strings.TrimSpace(u), "/") - trimmed = append(trimmed, t) - } - return trimmed -} - func (r *Runner) Declare(ctx context.Context, labels []string) (*connect.Response[runnerv1.DeclareResponse], error) { return r.client.Declare(ctx, connect.NewRequest(&runnerv1.DeclareRequest{ Version: ver.Version(), diff --git a/internal/pkg/client/http.go b/internal/pkg/client/http.go index bcd74ae..9f659df 100644 --- a/internal/pkg/client/http.go +++ b/internal/pkg/client/http.go @@ -14,7 +14,7 @@ import ( "github.com/bufbuild/connect-go" ) -func getHttpClient(endpoint string, insecure bool) *http.Client { +func getHTTPClient(endpoint string, insecure bool) *http.Client { if strings.HasPrefix(endpoint, "https://") && insecure { return &http.Client{ Transport: &http.Transport{ @@ -49,12 +49,12 @@ func New(endpoint string, insecure bool, uuid, token, version string, opts ...co return &HTTPClient{ PingServiceClient: pingv1connect.NewPingServiceClient( - getHttpClient(endpoint, insecure), + getHTTPClient(endpoint, insecure), baseURL, opts..., ), RunnerServiceClient: runnerv1connect.NewRunnerServiceClient( - getHttpClient(endpoint, insecure), + getHTTPClient(endpoint, insecure), baseURL, opts..., ), diff --git a/internal/pkg/config/config.example.yaml b/internal/pkg/config/config.example.yaml index 773fd20..0dc9f0d 100644 --- a/internal/pkg/config/config.example.yaml +++ b/internal/pkg/config/config.example.yaml @@ -1,5 +1,8 @@ # Example configuration file, it's safe to copy this as the default config file without any modification. +# You don't have to copy this file to your instance, +# just run `./act_runner generate-config > config.yaml` to generate a config file. + log: # The level of logging, can be trace, debug, info, warn, error, fatal level: info @@ -45,6 +48,10 @@ cache: # The port of the cache server. # 0 means to use a random available port. port: 0 + # The external cache server URL. Valid only when enable is true. + # If it's specified, act_runner will use this URL as the ACTIONS_CACHE_URL rather than start a server by itself. + # The URL should generally end with "/". + external_server: "" container: # Specifies the network to which the container will connect. diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index 8f81cc8..6b3c6e6 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -34,10 +34,11 @@ type Runner struct { // Cache represents the configuration for caching. type Cache struct { - Enabled *bool `yaml:"enabled"` // Enabled indicates whether caching is enabled. It is a pointer to distinguish between false and not set. If not set, it will be true. - Dir string `yaml:"dir"` // Dir specifies the directory path for caching. - Host string `yaml:"host"` // Host specifies the caching host. - Port uint16 `yaml:"port"` // Port specifies the caching port. + Enabled *bool `yaml:"enabled"` // Enabled indicates whether caching is enabled. It is a pointer to distinguish between false and not set. If not set, it will be true. + Dir string `yaml:"dir"` // Dir specifies the directory path for caching. + Host string `yaml:"host"` // Host specifies the caching host. + Port uint16 `yaml:"port"` // Port specifies the caching port. + ExternalServer string `yaml:"external_server"` // ExternalServer specifies the URL of external cache server } // Container represents the configuration for the container. @@ -119,7 +120,7 @@ func LoadDefault(file string) (*Config, error) { } if cfg.Host.WorkdirParent == "" { home, _ := os.UserHomeDir() - cfg.Container.WorkdirParent = filepath.Join(home, ".cache", "act") + cfg.Host.WorkdirParent = filepath.Join(home, ".cache", "act") } if cfg.Runner.FetchTimeout <= 0 { cfg.Runner.FetchTimeout = 5 * time.Second diff --git a/internal/pkg/labels/labels_test.go b/internal/pkg/labels/labels_test.go index dbef1ef..e46a27b 100644 --- a/internal/pkg/labels/labels_test.go +++ b/internal/pkg/labels/labels_test.go @@ -55,9 +55,8 @@ func TestParse(t *testing.T) { if tt.wantErr { require.Error(t, err) return - } else { - require.NoError(t, err) } + require.NoError(t, err) assert.DeepEqual(t, got, tt.want) }) }