Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Retro fit config to separate core and repo
  • Loading branch information
sourishkrout committed Apr 12, 2024
commit f871d294acd2a995c9e902bdc16b1a8ca980bc8a
92 changes: 47 additions & 45 deletions experimental/runme.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,55 @@
# You can test it with the "runme beta" commands.
version: v1alpha1

# Indicate the root of the runme project. "." means that
# the project root directory will be used.
project:
dir: "."
# If true, the project root will be searched upwards starting from "dir".
# If found, the repo root will be used as the project root.
find_repo_upward: true
ignore:
- "node_modules"
- ".venv"
disable_gitignore: false
repo:
# The list of filters to apply to blocks.
# "condition" must return a boolean value.
# You can learn about the syntax at https://expr-lang.org/docs/language-definition.
# Available fields are defined in [config.FilterDocumentEnv] and [config.FilterBlockEnv].
filters:
# Do not allow unnamed code blocks.
- type: "FILTER_TYPE_BLOCK"
condition: "is_named"
# Do not allow code blocks without a language.
- type: "FILTER_TYPE_BLOCK"
condition: "language != ''"
# Do not allow code blocks starting with "test".
- type: "FILTER_TYPE_BLOCK"
condition: "!hasPrefix(name, 'test')"

# It's possible to point at a single file as well.
# filename: "README.md"
core:
# Indicate the root of the runme project. "." means that
# the project root directory will be used.
project:
dir: "."
# If true, the project root will be searched upwards starting from "dir".
# If found, the repo root will be used as the project root.
find_repo_upward: true
ignore:
- "node_modules"
- ".venv"
disable_gitignore: false

# List of dotenv files to load.
env:
use_system_env: true
sources:
- ".env"
- ".env.local"
# It's possible to point at a single file as well.
# filename: "README.md"

# The list of filters to apply to blocks.
# "condition" must return a boolean value.
# You can learn about the syntax at https://expr-lang.org/docs/language-definition.
# Available fields are defined in [config.FilterDocumentEnv] and [config.FilterBlockEnv].
filters:
# Do not allow unnamed code blocks.
- type: "FILTER_TYPE_BLOCK"
condition: "is_named"
# Do not allow code blocks without a language.
- type: "FILTER_TYPE_BLOCK"
condition: "language != ''"
# Do not allow code blocks starting with "test".
- type: "FILTER_TYPE_BLOCK"
condition: "!hasPrefix(name, 'test')"
# List of dotenv files to load.
env:
use_system_env: true
sources:
- ".env"
- ".env.local"

server:
# Also unix:///path/to/file.sock is supported.
address: localhost:7890
tls:
enabled: true
# If not specified, default paths will be used.
# cert_file: "/path/to/cert.pem"
# key_file: "/path/to/key.pem"
server:
# Also unix:///path/to/file.sock is supported.
address: localhost:7890
tls:
enabled: true
# If not specified, default paths will be used.
# cert_file: "/path/to/cert.pem"
# key_file: "/path/to/key.pem"

log:
enabled: true
path: "/var/tmp/runme.log"
verbose: true
log:
enabled: true
path: "/var/tmp/runme.log"
verbose: true
68 changes: 40 additions & 28 deletions internal/api/runme/config/v1alpha1/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import "buf/validate/validate.proto";

option go_package = "github.com/stateful/runme/internal/gen/proto/go/runme/config/v1alpha1;configv1alpha1";

// Config describes the configuration of the runme tools, including CLI, server, and clients like VS Code extension.
message Config {
// ConfigCore describes system-level configuration of the runme toolchain.
message ConfigCore {
// source is a source of Markdown files to look into.
oneof source {
option (buf.validate.oneof).required = true;
Expand All @@ -22,11 +22,6 @@ message Config {
// env is the environment variables configuration.
Env env = 3;

// filters is a list of filters to apply.
// Filters can be applied to documents or
// individual code blocks.
repeated Filter filters = 5;

// log contains the log configuration.
Log log = 7;

Expand All @@ -47,27 +42,6 @@ message Config {
bool disable_gitignore = 4;
}

message Filter {
// type is the type of the filter.
FilterType type = 1 [(buf.validate.field).enum.defined_only = true];

// condition is the filter program to execute for each document or block,
// depending on the filter type.
//
// The condition should be a valid Expr expression and it should return a boolean value.
// You can read more about the Expr syntax on https://expr-lang.org/.
string condition = 2 [
(buf.validate.field).string.min_len = 1,
(buf.validate.field).string.max_len = 1024
];
}

enum FilterType {
FILTER_TYPE_UNSPECIFIED = 0;
FILTER_TYPE_BLOCK = 1;
FILTER_TYPE_DOCUMENT = 2;
}

message Env {
// use_system_env indicates whether to use the system environment variables.
bool use_system_env = 1;
Expand Down Expand Up @@ -99,3 +73,41 @@ message Config {
}
}
}

// ConfigRepo describes repo-level configuration of the runme toolchain.
message ConfigRepo {
// filters is a list of filters to apply.
// Filters can be applied to documents or
// individual code blocks.
repeated Filter filters = 5;

message Filter {
// type is the type of the filter.
FilterType type = 1 [(buf.validate.field).enum.defined_only = true];

// condition is the filter program to execute for each document or block,
// depending on the filter type.
//
// The condition should be a valid Expr expression and it should return a boolean value.
// You can read more about the Expr syntax on https://expr-lang.org/.
string condition = 2 [
(buf.validate.field).string.min_len = 1,
(buf.validate.field).string.max_len = 1024
];
}

enum FilterType {
FILTER_TYPE_UNSPECIFIED = 0;
FILTER_TYPE_BLOCK = 1;
FILTER_TYPE_DOCUMENT = 2;
}
}

// Config describes the configuration of the runme toolchain, including CLI, server, and clients like VS Code extension.
message Config {
// core is the system-level configuration.
ConfigCore core = 1;

// repo is the repo-level configuration.
ConfigRepo repo = 2;
}
4 changes: 2 additions & 2 deletions internal/cmd/beta/beta_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ All commands use the runme.yaml configuration file.`,
return autoconfig.Invoke(func(cfg *config.Config) error {
// Override the filename if provided.
if cFlags.filename != "" {
cfg.Filename = cFlags.filename
cfg.Core.Filename = cFlags.filename
}

// Add a filter to run only tasks from the specified categories.
if len(cFlags.categories) > 0 {
cfg.Filters = append(cfg.Filters, &config.Filter{
cfg.Repo.Filters = append(cfg.Repo.Filters, &config.Filter{
Type: config.FilterTypeBlock,
Condition: `len(intersection(categories, extra.categories)) > 0`,
Extra: map[string]interface{}{"categories": cFlags.categories},
Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/beta/server/grpcurl_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ func getDescriptorSource(ctx context.Context, cfg *config.Config) (grpcurl.Descr
}

func dialServer(ctx context.Context, cfg *config.Config) (*grpc.ClientConn, error) {
tlsConf, err := runmetls.LoadClientConfig(cfg.ServerTLSCertFile, cfg.ServerTLSKeyFile)
tlsConf, err := runmetls.LoadClientConfig(cfg.Core.ServerTLSCertFile, cfg.Core.ServerTLSKeyFile)
if err != nil {
return nil, err
}

creds := credentials.NewTLS(tlsConf)

network, addr := "tcp", cfg.ServerAddress
network, addr := "tcp", cfg.Core.ServerAddress
if strings.HasPrefix(addr, "unix://") {
network, addr = "unix", strings.TrimPrefix(addr, "unix://")
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/beta/server/server_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func Cmd() *cobra.Command {
) error {
// For the server commands, we want to always log to stdout.
// TODO(adamb): there might be a need to separate client and server logs.
cfg.LogPath = ""
cfg.Core.LogPath = ""
return nil
},
)
Expand Down
12 changes: 6 additions & 6 deletions internal/cmd/beta/server/server_start_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ func serverStartCmd() *cobra.Command {
defer logger.Sync()

serverCfg := &server.Config{
Address: cfg.ServerAddress,
CertFile: cfg.ServerTLSCertFile,
KeyFile: cfg.ServerTLSKeyFile,
TLSEnabled: cfg.ServerTLSEnabled,
Address: cfg.Core.ServerAddress,
CertFile: cfg.Core.ServerTLSCertFile,
KeyFile: cfg.Core.ServerTLSKeyFile,
TLSEnabled: cfg.Core.ServerTLSEnabled,
}

logger.Debug("server config", zap.Any("config", serverCfg))
Expand All @@ -39,12 +39,12 @@ func serverStartCmd() *cobra.Command {
}

// When using a unix socket, we want to create a file with server's PID.
if path := pidFileNameFromAddr(cfg.ServerAddress); path != "" {
if path := pidFileNameFromAddr(cfg.Core.ServerAddress); path != "" {
logger.Debug("creating PID file", zap.String("path", path))
if err := createFileWithPID(path); err != nil {
return errors.WithStack(err)
}
defer os.Remove(cfg.ServerAddress)
defer os.Remove(cfg.Core.ServerAddress)
}

return errors.WithStack(s.Serve())
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/beta/server/server_stop_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func serverStopCmd() *cobra.Command {

logger.Debug("stopping the server by looking for runme.pid")

path := pidFileNameFromAddr(cfg.ServerAddress)
path := pidFileNameFromAddr(cfg.Core.ServerAddress)
if path == "" {
return errors.New("server address is not a unix socket")
}
Expand Down
38 changes: 19 additions & 19 deletions internal/config/autoconfig/autoconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,20 +102,20 @@ func getConfig(userCfgDir UserConfigDir, viper *viper.Viper) (*config.Config, er
return nil, err
}

if cfg.ServerTLSEnabled {
if cfg.ServerTLSCertFile == "" {
cfg.ServerTLSCertFile = filepath.Join(string(userCfgDir), "cert.pem")
if cfg.Core.ServerTLSEnabled {
if cfg.Core.ServerTLSCertFile == "" {
cfg.Core.ServerTLSCertFile = filepath.Join(string(userCfgDir), "cert.pem")
}
if cfg.ServerTLSKeyFile == "" {
cfg.ServerTLSKeyFile = filepath.Join(string(userCfgDir), "key.pem")
if cfg.Core.ServerTLSKeyFile == "" {
cfg.Core.ServerTLSKeyFile = filepath.Join(string(userCfgDir), "key.pem")
}
}

return cfg, nil
}

func getLogger(c *config.Config) (*zap.Logger, error) {
if c == nil || !c.LogEnabled {
if c == nil || !c.Core.LogEnabled {
return zap.NewNop(), nil
}

Expand All @@ -132,16 +132,16 @@ func getLogger(c *config.Config) (*zap.Logger, error) {
ErrorOutputPaths: []string{"stderr"},
}

if c.LogVerbose {
if c.Core.LogVerbose {
zapConfig.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
zapConfig.Development = true
zapConfig.Encoding = "console"
zapConfig.EncoderConfig = zap.NewDevelopmentEncoderConfig()
}

if c.LogPath != "" {
zapConfig.OutputPaths = []string{c.LogPath}
zapConfig.ErrorOutputPaths = []string{c.LogPath}
if c.Core.LogPath != "" {
zapConfig.OutputPaths = []string{c.Core.LogPath}
zapConfig.ErrorOutputPaths = []string{c.Core.LogPath}
}

l, err := zapConfig.Build()
Expand All @@ -153,24 +153,24 @@ func getProject(c *config.Config, logger *zap.Logger) (*project.Project, error)
project.WithLogger(logger),
}

if c.Filename != "" {
return project.NewFileProject(c.Filename, opts...)
if c.Core.Filename != "" {
return project.NewFileProject(c.Core.Filename, opts...)
}

projDir := c.ProjectDir
projDir := c.Core.ProjectDir
// If no project directory is specified, use the current directory.
if projDir == "" {
projDir = "."
}

opts = append(
opts,
project.WithIgnoreFilePatterns(c.IgnorePaths...),
project.WithRespectGitignore(!c.DisableGitignore),
project.WithEnvFilesReadOrder(c.EnvSourceFiles),
project.WithIgnoreFilePatterns(c.Core.IgnorePaths...),
project.WithRespectGitignore(!c.Core.DisableGitignore),
project.WithEnvFilesReadOrder(c.Core.EnvSourceFiles),
)

if c.FindRepoUpward {
if c.Core.FindRepoUpward {
opts = append(opts, project.WithFindRepoUpward())
}

Expand All @@ -180,7 +180,7 @@ func getProject(c *config.Config, logger *zap.Logger) (*project.Project, error)
func getProjectFilters(c *config.Config) ([]project.Filter, error) {
var filters []project.Filter

for _, filter := range c.Filters {
for _, filter := range c.Repo.Filters {
filter := filter

switch filter.Type {
Expand Down Expand Up @@ -228,7 +228,7 @@ func getProjectFilters(c *config.Config) ([]project.Filter, error) {
func getSession(cfg *config.Config, proj *project.Project) (*command.Session, error) {
sess := command.NewSession()

if cfg.UseSystemEnv {
if cfg.Core.UseSystemEnv {
if err := sess.SetEnv(os.Environ()...); err != nil {
return nil, err
}
Expand Down
4 changes: 3 additions & 1 deletion internal/config/autoconfig/autoconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ func TestInvokeAll(t *testing.T) {
// Create a runme.yaml using the README.md file from above.
// This won't work with the project as it requires the project
// to be a subdirectory of the current working directory.
configYAML := fmt.Sprintf("version: v1alpha1\nfilename: %s\n", readmeFilePath)
configYAML := fmt.Sprintf("version: v1alpha1\ncore:\n filename: %s\n", readmeFilePath)

fmt.Println(string(configYAML))

// Create a runme.yaml file in the temp directory.
err = os.WriteFile(filepath.Join(tempDir, "/runme.yaml"), []byte(configYAML), 0o600)
Expand Down
Loading