Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate project and runtime options in runme.yaml #584

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
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
66 changes: 34 additions & 32 deletions experimental/runme.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
# 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.
# Settings that apply on at the project level.
project:
dir: "."
# Indicate the root of the runme project. "." means that
# the project root directory will be used.
root: "."
# 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
Expand All @@ -18,38 +19,39 @@ project:
- ".venv"
disable_gitignore: false

# It's possible to point at a single file as well.
# filename: "README.md"
# It's possible to point the project at a single file.
# filename: "README.md"

# List of dotenv files to load.
env:
use_system_env: true
sources:
- ".env"
- ".env.local"
# List of dotenv files to load.
env:
use_system_env: false
sources:
- ".env"
- ".env.local"

# Optional Docker configuration to run code blocks in a container.
docker:
enabled: false
image: runme-runtime:latest
build:
context: ./experimental/docker
dockerfile: Dockerfile
# 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')"

# 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')"
runtime:
# Optional Docker configuration to run code blocks in a container.
docker:
enabled: false
image: runme-runtime:latest
build:
context: ./experimental/docker
dockerfile: Dockerfile

server:
# Also unix:///path/to/file.sock is supported.
Expand Down
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.ProjectFilename = 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.ProjectFilters = append(cfg.ProjectFilters, &config.Filter{
Type: config.FilterTypeBlock,
Condition: `len(intersection(categories, extra.categories)) > 0`,
Extra: map[string]interface{}{"categories": cFlags.categories},
Expand Down
26 changes: 13 additions & 13 deletions internal/config/autoconfig/autoconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,24 +101,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.ProjectFilename != "" {
return project.NewFileProject(c.ProjectFilename, opts...)
}

projDir := c.ProjectDir
projDir := c.ProjectRoot
// 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.ProjectIgnorePaths...),
project.WithRespectGitignore(!c.ProjectDisableGitignore),
project.WithEnvFilesReadOrder(c.ProjectEnvSources),
)

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

Expand All @@ -128,7 +128,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.ProjectFilters {
filter := filter

switch filter.Type {
Expand Down Expand Up @@ -197,11 +197,11 @@ func getRootConfig(cfgLoader *config.Loader, userCfgDir UserConfigDir) (*config.
}

func getRuntime(c *config.Config, logger *zap.Logger) (command.Runtime, error) {
if c.DockerEnabled {
if c.RuntimeDockerEnabled {
docker, err := dockerexec.New(&dockerexec.Options{
BuildContext: c.DockerBuildContext,
Dockerfile: c.DockerBuildDockerfile,
Image: c.DockerImage,
BuildContext: c.RuntimeDockerBuildContext,
Dockerfile: c.RuntimeDockerBuildDockerfile,
Image: c.RuntimeDockerImage,
Logger: logger,
})
if err != nil {
Expand All @@ -215,7 +215,7 @@ func getRuntime(c *config.Config, logger *zap.Logger) (command.Runtime, error) {
func getSession(cfg *config.Config, proj *project.Project) (*command.Session, error) {
sess := command.NewSession()

if cfg.UseSystemEnv {
if cfg.ProjectEnvUseSystemEnv {
if err := sess.SetEnv(os.Environ()...); err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/config/autoconfig/autoconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestInvokeConfig(t *testing.T) {
Data: []byte("Hello, World!"),
},
"runme.yaml": {
Data: []byte(fmt.Sprintf("version: v1alpha1\nfilename: %s\n", "README.md")),
Data: []byte(fmt.Sprintf("version: v1alpha1\nproject:\n filename: %s\n", "README.md")),
},
}

Expand Down
107 changes: 42 additions & 65 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,37 +18,28 @@ import (
// Config is a flatten configuration of runme.yaml. The purpose of it is to
// unify all the different configuration versions into a single struct.
type Config struct {
// Dir- or git-based project fields.
DisableGitignore bool
IgnorePaths []string
FindRepoUpward bool
ProjectDir string
ProjectRoot string
ProjectFilename string
ProjectFindRepoUpward bool
ProjectIgnorePaths []string
ProjectDisableGitignore bool
ProjectEnvUseSystemEnv bool
ProjectEnvSources []string
ProjectFilters []*Filter

RuntimeDockerEnabled bool
RuntimeDockerImage string
RuntimeDockerBuildContext string
RuntimeDockerBuildDockerfile string

// Filemode fields.
Filename string

// Environment variable fields.
EnvSourceFiles []string
UseSystemEnv bool

Filters []*Filter

// Log related fields.
LogEnabled bool
LogPath string
LogVerbose bool

// Server related fields.
ServerAddress string
ServerTLSEnabled bool
ServerTLSCertFile string
ServerTLSKeyFile string

// Docker configuration.
DockerEnabled bool
DockerImage string
DockerBuildContext string
DockerBuildDockerfile string
LogEnabled bool
LogPath string
LogVerbose bool
}

func ParseYAML(data []byte) (*Config, error) {
Expand Down Expand Up @@ -122,42 +113,41 @@ func parseYAMLv1alpha1(data []byte) (*configv1alpha1.Config, error) {

func configV1alpha1ToConfig(c *configv1alpha1.Config) (*Config, error) {
project := c.GetProject()
runtime := c.GetRuntime()
server := c.GetServer()
log := c.GetLog()

var filters []*Filter
for _, f := range c.GetFilters() {
for _, f := range c.GetProject().GetFilters() {
filters = append(filters, &Filter{
Type: f.GetType().String(),
Condition: f.GetCondition(),
})
}

cfg := &Config{
ProjectDir: project.GetDir(),
FindRepoUpward: project.GetFindRepoUpward(),
IgnorePaths: project.GetIgnorePaths(),
DisableGitignore: project.GetDisableGitignore(),

Filename: c.GetFilename(),

UseSystemEnv: c.GetEnv().GetUseSystemEnv(),
EnvSourceFiles: c.GetEnv().GetSources(),

Filters: filters,
ProjectRoot: project.GetRoot(),
ProjectFilename: project.GetFilename(),
ProjectFindRepoUpward: project.GetFindRepoUpward(),
ProjectIgnorePaths: project.GetIgnorePaths(),
ProjectDisableGitignore: project.GetDisableGitignore(),
ProjectEnvUseSystemEnv: project.GetEnv().GetUseSystemEnv(),
ProjectEnvSources: project.GetEnv().GetSources(),
ProjectFilters: filters,

RuntimeDockerEnabled: runtime.GetDocker().GetEnabled(),
RuntimeDockerImage: runtime.GetDocker().GetImage(),
RuntimeDockerBuildContext: runtime.GetDocker().GetBuild().GetContext(),
RuntimeDockerBuildDockerfile: runtime.GetDocker().GetBuild().GetDockerfile(),

ServerAddress: server.GetAddress(),
ServerTLSEnabled: server.GetTls().GetEnabled(),
ServerTLSCertFile: server.GetTls().GetCertFile(),
ServerTLSKeyFile: server.GetTls().GetKeyFile(),

LogEnabled: log.GetEnabled(),
LogPath: log.GetPath(),
LogVerbose: log.GetVerbose(),

ServerAddress: c.GetServer().GetAddress(),
ServerTLSEnabled: c.GetServer().GetTls().GetEnabled(),
ServerTLSCertFile: c.GetServer().GetTls().GetCertFile(),
ServerTLSKeyFile: c.GetServer().GetTls().GetKeyFile(),

DockerEnabled: c.GetDocker().GetEnabled(),
DockerImage: c.GetDocker().GetImage(),
DockerBuildContext: c.GetDocker().GetBuild().GetContext(),
DockerBuildDockerfile: c.GetDocker().GetBuild().GetDockerfile(),
}

return cfg, nil
Expand All @@ -169,38 +159,25 @@ func validateConfig(cfg *Config) error {
cwd = "."
}

if err := validateProjectDir(cfg, cwd); err != nil {
if err := validateInsideCwd(cfg.ProjectRoot, cwd); err != nil {
return errors.Wrap(err, "failed to validate project dir")
}

if err := validateFilename(cfg, cwd); err != nil {
if err := validateInsideCwd(cfg.ProjectFilename, cwd); err != nil {
return errors.Wrap(err, "failed to validate filename")
}

return nil
}

func validateProjectDir(cfg *Config, cwd string) error {
rel, err := filepath.Rel(cwd, filepath.Join(cwd, cfg.ProjectDir))
if err != nil {
return errors.WithStack(err)
}
if strings.HasPrefix(rel, "..") {
return errors.New("outside of current working directory")
}

return nil
}

func validateFilename(cfg *Config, cwd string) error {
rel, err := filepath.Rel(cwd, filepath.Join(cwd, cfg.Filename))
func validateInsideCwd(path, cwd string) error {
rel, err := filepath.Rel(cwd, filepath.Join(cwd, path))
if err != nil {
return errors.WithStack(err)
}
if strings.HasPrefix(rel, "..") {
return errors.New("outside of current working directory")
return errors.New("outside of the current working directory")
}

return nil
}

Expand Down
Loading
Loading