diff --git a/internal/cmd/beta/beta_cmd.go b/internal/cmd/beta/beta_cmd.go index a00edcdae..65620a890 100644 --- a/internal/cmd/beta/beta_cmd.go +++ b/internal/cmd/beta/beta_cmd.go @@ -6,6 +6,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/pflag" + "go.uber.org/zap" "github.com/stateful/runme/v3/internal/cmd/beta/server" "github.com/stateful/runme/v3/internal/config" @@ -36,7 +37,7 @@ All commands use the runme.yaml configuration file.`, cmd.SetErr(io.Discard) } - err := autoconfig.InvokeForCommand(func(cfg *config.Config) error { + err := autoconfig.InvokeForCommand(func(cfg *config.Config, log *zap.Logger) error { // Override the filename if provided. if cFlags.filename != "" { cfg.Project.Filename = cFlags.filename @@ -54,10 +55,13 @@ All commands use the runme.yaml configuration file.`, ) } + log.Info("final configuration", zap.Any("config", cfg)) + return nil }) - // print the error to stderr but don't return it because error modes - // are neither fully baked yet nor ready for users to consume + + // Print the error to stderr but don't return it because error modes + // are neither fully baked yet nor ready for users to consume. if err != nil { _, _ = fmt.Fprintf(cmd.ErrOrStderr(), "%s\n", err) } diff --git a/internal/cmd/beta/run_cmd.go b/internal/cmd/beta/run_cmd.go index 8bcd1e9a0..1df64b12b 100644 --- a/internal/cmd/beta/run_cmd.go +++ b/internal/cmd/beta/run_cmd.go @@ -19,7 +19,7 @@ import ( ) func runCmd(*commonFlags) *cobra.Command { - var serverAddress string + var remote bool cmd := cobra.Command{ Use: "run [command1 command2 ...]", @@ -40,7 +40,7 @@ Run all blocks from the "setup" and "teardown" tags: RunE: func(cmd *cobra.Command, args []string) error { return autoconfig.InvokeForCommand( func( - client *runnerv2client.Client, + clientFactory autoconfig.ClientFactory, cmdFactory command.Factory, filters []project.Filter, logger *zap.Logger, @@ -74,9 +74,10 @@ Run all blocks from the "setup" and "teardown" tags: ctx := cmd.Context() - if serverAddress != "" && client != nil { - if serverAddress != "local" { - return errors.New("only local server is supported") + if remote { + client, err := clientFactory() + if err != nil { + return err } sessionResp, err := client.CreateSession( @@ -122,7 +123,7 @@ Run all blocks from the "setup" and "teardown" tags: }, } - cmd.Flags().StringVarP(&serverAddress, "server", "s", "", "Server address to connect to. Use 'local' for local server.") + cmd.Flags().BoolVarP(&remote, "remote", "r", false, "Run commands on a remote server.") return &cmd } diff --git a/internal/config/autoconfig/autoconfig.go b/internal/config/autoconfig/autoconfig.go index e344308cc..3eb648c8c 100644 --- a/internal/config/autoconfig/autoconfig.go +++ b/internal/config/autoconfig/autoconfig.go @@ -66,6 +66,7 @@ func mustProvide(err error) { func init() { mustProvide(container.Provide(getClient)) + mustProvide(container.Provide(getClientFactory)) mustProvide(container.Provide(getCommandFactory)) mustProvide(container.Provide(getConfigLoader)) mustProvide(container.Provide(getDocker)) @@ -76,6 +77,39 @@ func init() { mustProvide(container.Provide(getUserConfigDir)) } +func getClient(cfg *config.Config, logger *zap.Logger) (*runnerv2client.Client, error) { + if cfg.Server == nil { + return nil, nil + } + + var opts []grpc.DialOption + + if cfg.Server.Tls != nil && cfg.Server.Tls.Enabled { + tlsConfig, err := runmetls.LoadClientConfig(cfg.Server.Tls.CertFile, cfg.Server.Tls.KeyFile) + if err != nil { + return nil, errors.WithStack(err) + } + creds := credentials.NewTLS(tlsConfig) + opts = append(opts, grpc.WithTransportCredentials(creds)) + } else { + opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) + } + + return runnerv2client.New( + cfg.Server.Address, + logger, + opts..., + ) +} + +type ClientFactory func() (*runnerv2client.Client, error) + +func getClientFactory(cfg *config.Config, logger *zap.Logger) ClientFactory { + return func() (*runnerv2client.Client, error) { + return getClient(cfg, logger) + } +} + func getCommandFactory(docker *dockerexec.Docker, logger *zap.Logger, proj *project.Project) command.Factory { return command.NewFactory( command.WithDocker(docker), @@ -112,31 +146,6 @@ func getDocker(c *config.Config, logger *zap.Logger) (*dockerexec.Docker, error) return dockerexec.New(options) } -func getClient(cfg *config.Config, logger *zap.Logger) (*runnerv2client.Client, error) { - if cfg.Server == nil { - return nil, nil - } - - var opts []grpc.DialOption - - if cfg.Server.Tls != nil && cfg.Server.Tls.Enabled { - tlsConfig, err := runmetls.LoadClientConfig(cfg.Server.Tls.CertFile, cfg.Server.Tls.KeyFile) - if err != nil { - return nil, errors.WithStack(err) - } - creds := credentials.NewTLS(tlsConfig) - opts = append(opts, grpc.WithTransportCredentials(creds)) - } else { - opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) - } - - return runnerv2client.New( - cfg.Server.Address, - logger, - opts..., - ) -} - func getLogger(c *config.Config) (*zap.Logger, error) { if c == nil || c.Log == nil || !c.Log.Enabled { return zap.NewNop(), nil @@ -176,32 +185,28 @@ func getProject(c *config.Config, logger *zap.Logger) (*project.Project, error) project.WithLogger(logger), } - if c.Project.Filename == "" { + if c.Project.Filename != "" { return project.NewFileProject(c.Project.Filename, opts...) } - if c.Project.Root != "" { - projDir := c.Project.Root - // If no project directory is specified, use the current directory. - if projDir == "" { - projDir = "." - } - - opts = append( - opts, - project.WithIgnoreFilePatterns(c.Project.Ignore...), - project.WithRespectGitignore(!c.Project.DisableGitignore), - project.WithEnvFilesReadOrder(c.Project.Env.Sources), - ) + projDir := c.Project.Root + // If no project directory is specified, use the current directory. + if projDir == "" { + projDir = "." + } - if c.Project.FindRepoUpward { - opts = append(opts, project.WithFindRepoUpward()) - } + opts = append( + opts, + project.WithIgnoreFilePatterns(c.Project.Ignore...), + project.WithRespectGitignore(!c.Project.DisableGitignore), + project.WithEnvFilesReadOrder(c.Project.Env.Sources), + ) - return project.NewDirProject(projDir, opts...) + if c.Project.FindRepoUpward { + opts = append(opts, project.WithFindRepoUpward()) } - return nil, nil + return project.NewDirProject(projDir, opts...) } func getProjectFilters(c *config.Config) ([]project.Filter, error) { diff --git a/internal/config/config.schema.json b/internal/config/config.schema.json index dd9202857..85e2e24e3 100644 --- a/internal/config/config.schema.json +++ b/internal/config/config.schema.json @@ -139,6 +139,17 @@ "address" ] }, + "client": { + "type": "object", + "properties": { + "server_address": { + "type": "string" + } + }, + "required": [ + "server_address" + ] + }, "log": { "type": "object", "properties": {