diff --git a/api/v1alpha1/git/git_config.go b/api/v1alpha1/git/git_config.go index 10535c2ff..09eaa0b7f 100644 --- a/api/v1alpha1/git/git_config.go +++ b/api/v1alpha1/git/git_config.go @@ -8,6 +8,7 @@ type GitConfig struct { // GitLivereloadConfig represents the Git livereload configuration type GitLivereloadConfig struct { Enabled *bool `yaml:"enabled"` + RsyncInclude *string `yaml:"rsync_include,omitempty"` RsyncExclude *string `yaml:"rsync_exclude,omitempty"` RsyncProtect *string `yaml:"rsync_protect,omitempty"` Username *string `yaml:"username,omitempty"` @@ -26,6 +27,9 @@ func (base *GitConfig) Merge(overlay *GitConfig) { if overlay.Livereload.Enabled != nil { base.Livereload.Enabled = overlay.Livereload.Enabled } + if overlay.Livereload.RsyncInclude != nil { + base.Livereload.RsyncInclude = overlay.Livereload.RsyncInclude + } if overlay.Livereload.RsyncExclude != nil { base.Livereload.RsyncExclude = overlay.Livereload.RsyncExclude } @@ -59,6 +63,7 @@ func (c *GitConfig) Copy() *GitConfig { if c.Livereload != nil { livereloadCopy = &GitLivereloadConfig{ Enabled: c.Livereload.Enabled, + RsyncInclude: c.Livereload.RsyncInclude, RsyncExclude: c.Livereload.RsyncExclude, RsyncProtect: c.Livereload.RsyncProtect, Username: c.Livereload.Username, diff --git a/api/v1alpha1/git/git_config_test.go b/api/v1alpha1/git/git_config_test.go index c7746c412..7ea800c29 100644 --- a/api/v1alpha1/git/git_config_test.go +++ b/api/v1alpha1/git/git_config_test.go @@ -13,6 +13,7 @@ func TestGitConfig_Merge(t *testing.T) { } *base.Livereload = GitLivereloadConfig{ Enabled: ptrBool(true), + RsyncInclude: ptrString("include-pattern"), RsyncExclude: ptrString("exclude-pattern"), RsyncProtect: ptrString("protect-pattern"), Username: ptrString("user"), @@ -25,6 +26,7 @@ func TestGitConfig_Merge(t *testing.T) { overlay := &GitConfig{ Livereload: &GitLivereloadConfig{ Enabled: ptrBool(false), + RsyncInclude: ptrString("new-include-pattern"), RsyncExclude: ptrString("new-exclude-pattern"), RsyncProtect: ptrString("new-protect-pattern"), Username: ptrString("new-user"), @@ -40,6 +42,9 @@ func TestGitConfig_Merge(t *testing.T) { if base.Livereload.Enabled == nil || *base.Livereload.Enabled != false { t.Errorf("Enabled mismatch: expected %v, got %v", false, *base.Livereload.Enabled) } + if base.Livereload.RsyncInclude == nil || *base.Livereload.RsyncInclude != "new-include-pattern" { + t.Errorf("RsyncInclude mismatch: expected %v, got %v", "new-include-pattern", *base.Livereload.RsyncInclude) + } if base.Livereload.RsyncExclude == nil || *base.Livereload.RsyncExclude != "new-exclude-pattern" { t.Errorf("RsyncExclude mismatch: expected %v, got %v", "new-exclude-pattern", *base.Livereload.RsyncExclude) } @@ -71,6 +76,7 @@ func TestGitConfig_Merge(t *testing.T) { overlay := &GitConfig{ Livereload: &GitLivereloadConfig{ Enabled: ptrBool(true), + RsyncInclude: ptrString("include-pattern"), RsyncExclude: ptrString("exclude-pattern"), RsyncProtect: ptrString("protect-pattern"), Username: ptrString("user"), @@ -86,6 +92,9 @@ func TestGitConfig_Merge(t *testing.T) { if base.Livereload.Enabled == nil || *base.Livereload.Enabled != true { t.Errorf("Enabled mismatch: expected %v, got %v", true, *base.Livereload.Enabled) } + if base.Livereload.RsyncInclude == nil || *base.Livereload.RsyncInclude != "include-pattern" { + t.Errorf("RsyncInclude mismatch: expected %v, got %v", "include-pattern", *base.Livereload.RsyncInclude) + } if base.Livereload.RsyncExclude == nil || *base.Livereload.RsyncExclude != "exclude-pattern" { t.Errorf("RsyncExclude mismatch: expected %v, got %v", "exclude-pattern", *base.Livereload.RsyncExclude) } @@ -118,6 +127,7 @@ func TestGitConfig_Copy(t *testing.T) { } *original.Livereload = GitLivereloadConfig{ Enabled: ptrBool(true), + RsyncInclude: ptrString("include-pattern"), RsyncExclude: ptrString("exclude-pattern"), RsyncProtect: ptrString("protect-pattern"), Username: ptrString("user"), diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 31d86fb77..5fc7791bb 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -179,6 +179,7 @@ Configures details related to the local git livereload server git: livereload: enabled: true + rsync_include: "" rsync_exclude: .windsor,.terraform,data,.volumes,.venv rsync_protect: flux-system username: local @@ -191,6 +192,7 @@ git: | Field | Type | Description | |----------------|----------|--------------------------------------------------------------| | `enabled` | `bool` | Indicates whether the livereload feature is enabled. | +| `rsync_include`| `string` | Comma-separated list of patterns to include in rsync. When set, only files matching these patterns will be synchronized. | | `rsync_exclude`| `string` | Comma-separated list of patterns to exclude from rsync. | | `rsync_protect`| `string` | Specifies files or directories to protect during rsync. | | `username` | `string` | Username for authentication with the livereload server. | @@ -302,6 +304,7 @@ contexts: git: livereload: enabled: true + rsync_include: "" rsync_exclude: .windsor,.terraform,data,.volumes,.venv rsync_protect: flux-system username: local diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index 38aaff179..c8c6cc3fd 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -55,7 +55,7 @@ var commonDockerConfig = docker.DockerConfig{ var commonGitConfig = git.GitConfig{ Livereload: &git.GitLivereloadConfig{ Enabled: ptrBool(true), - RsyncExclude: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_RSYNC_EXCLUDE), + RsyncInclude: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_RSYNC_INCLUDE), RsyncProtect: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_RSYNC_PROTECT), Username: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_USERNAME), Password: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_PASSWORD), diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 8fd522345..b81635e70 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -5,7 +5,8 @@ import "time" // Default git livereload settings const ( // renovate: datasource=docker depName=ghcr.io/windsorcli/git-livereload-server - DEFAULT_GIT_LIVE_RELOAD_IMAGE = "ghcr.io/windsorcli/git-livereload:v0.1.1" + DEFAULT_GIT_LIVE_RELOAD_IMAGE = "ghcr.io/windsorcli/git-livereload:v0.2.0" + DEFAULT_GIT_LIVE_RELOAD_RSYNC_INCLUDE = "" DEFAULT_GIT_LIVE_RELOAD_RSYNC_EXCLUDE = ".windsor,.terraform,data,.volumes,.venv" DEFAULT_GIT_LIVE_RELOAD_RSYNC_PROTECT = "flux-system" DEFAULT_GIT_LIVE_RELOAD_USERNAME = "local" diff --git a/pkg/services/git_livereload_service.go b/pkg/services/git_livereload_service.go index 2752f4ae1..c5ac1a389 100644 --- a/pkg/services/git_livereload_service.go +++ b/pkg/services/git_livereload_service.go @@ -44,6 +44,7 @@ func (s *GitLivereloadService) GetComposeConfig() (*types.Config, error) { contextName := s.configHandler.GetContext() // Retrieve environment variables from config with defaults using Get* functions + rsyncInclude := s.configHandler.GetString("git.livereload.rsync_include", constants.DEFAULT_GIT_LIVE_RELOAD_RSYNC_INCLUDE) rsyncExclude := s.configHandler.GetString("git.livereload.rsync_exclude", constants.DEFAULT_GIT_LIVE_RELOAD_RSYNC_EXCLUDE) rsyncProtect := s.configHandler.GetString("git.livereload.rsync_protect", constants.DEFAULT_GIT_LIVE_RELOAD_RSYNC_PROTECT) gitUsername := s.configHandler.GetString("git.livereload.username", constants.DEFAULT_GIT_LIVE_RELOAD_USERNAME) @@ -61,6 +62,11 @@ func (s *GitLivereloadService) GetComposeConfig() (*types.Config, error) { "VERIFY_SSL": ptrString(fmt.Sprintf("%t", verifySsl)), } + // Add RSYNC_INCLUDE if it's not empty + if rsyncInclude != "" { + envVars["RSYNC_INCLUDE"] = ptrString(rsyncInclude) + } + // Add webhook URL if provided if webhookUrl != "" { envVars["WEBHOOK_URL"] = ptrString(webhookUrl) diff --git a/pkg/services/git_livereload_service_test.go b/pkg/services/git_livereload_service_test.go index bb5166d27..1eb8f7c07 100644 --- a/pkg/services/git_livereload_service_test.go +++ b/pkg/services/git_livereload_service_test.go @@ -98,4 +98,93 @@ func TestGitLivereloadService_GetComposeConfig(t *testing.T) { t.Fatalf("expected error retrieving project root, got %v", err) } }) + + t.Run("SuccessWithRsyncInclude", func(t *testing.T) { + // Given a mock config handler, shell, context, and service with rsync_include configured + mocks := setupMocks(t) + gitLivereloadService := NewGitLivereloadService(mocks.Injector) + err := gitLivereloadService.Initialize() + if err != nil { + t.Fatalf("Initialize() error = %v", err) + } + + // Set the service name + gitLivereloadService.SetName("git") + + // Configure rsync_include in the mock config + mocks.ConfigHandler.SetContextValue("git.livereload.rsync_include", "kustomize") + + // When GetComposeConfig is called + composeConfig, err := gitLivereloadService.GetComposeConfig() + if err != nil { + t.Fatalf("GetComposeConfig() error = %v", err) + } + + // Then verify the configuration contains the expected service with RSYNC_INCLUDE + expectedName := "git" + serviceFound := false + rsyncIncludeFound := false + + for _, service := range composeConfig.Services { + if service.Name == expectedName { + serviceFound = true + // Check if RSYNC_INCLUDE environment variable is set + if rsyncInclude, exists := service.Environment["RSYNC_INCLUDE"]; exists && rsyncInclude != nil { + if *rsyncInclude == "kustomize" { + rsyncIncludeFound = true + } + } + break + } + } + + if !serviceFound { + t.Errorf("expected service with name %q to be in the list of configurations", expectedName) + } + if !rsyncIncludeFound { + t.Errorf("expected RSYNC_INCLUDE environment variable to be set to 'kustomize'") + } + }) + + t.Run("SuccessWithoutRsyncInclude", func(t *testing.T) { + // Given a mock config handler, shell, context, and service without rsync_include configured + mocks := setupMocks(t) + gitLivereloadService := NewGitLivereloadService(mocks.Injector) + err := gitLivereloadService.Initialize() + if err != nil { + t.Fatalf("Initialize() error = %v", err) + } + + // Set the service name + gitLivereloadService.SetName("git") + + // When GetComposeConfig is called (using default empty rsync_include) + composeConfig, err := gitLivereloadService.GetComposeConfig() + if err != nil { + t.Fatalf("GetComposeConfig() error = %v", err) + } + + // Then verify the configuration doesn't contain RSYNC_INCLUDE when it's empty + expectedName := "git" + serviceFound := false + rsyncIncludePresent := false + + for _, service := range composeConfig.Services { + if service.Name == expectedName { + serviceFound = true + // Check if RSYNC_INCLUDE environment variable is NOT set when empty + if _, exists := service.Environment["RSYNC_INCLUDE"]; exists { + rsyncIncludePresent = true + } + break + } + } + + if !serviceFound { + t.Errorf("expected service with name %q to be in the list of configurations", expectedName) + } + if rsyncIncludePresent { + t.Errorf("expected RSYNC_INCLUDE environment variable to NOT be set when rsync_include is empty") + } + }) }