Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package terragrunt for openSUSE:Factory checked in at 2025-09-26 22:25:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/terragrunt (Old) and /work/SRC/openSUSE:Factory/.terragrunt.new.11973 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "terragrunt" Fri Sep 26 22:25:02 2025 rev:255 rq:1307264 version:0.87.7 Changes: -------- --- /work/SRC/openSUSE:Factory/terragrunt/terragrunt.changes 2025-09-25 18:47:04.358634481 +0200 +++ /work/SRC/openSUSE:Factory/.terragrunt.new.11973/terragrunt.changes 2025-09-26 22:26:46.719718320 +0200 @@ -1,0 +2,12 @@ +Fri Sep 26 05:30:54 UTC 2025 - Johannes Kastl <[email protected]> + +- Update to version 0.87.7: + * Bug Fixes + - Partial cache population fix + Resolved an issue that prevented the HCL partial cache from + being fully populated + * What's Changed + - chore: Fix for HclCache population in PartialParseConfigFile + by @denis256 in #4877 + +------------------------------------------------------------------- Old: ---- terragrunt-0.87.6.obscpio New: ---- terragrunt-0.87.7.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ terragrunt.spec ++++++ --- /var/tmp/diff_new_pack.jNGtaR/_old 2025-09-26 22:26:47.855766232 +0200 +++ /var/tmp/diff_new_pack.jNGtaR/_new 2025-09-26 22:26:47.859766401 +0200 @@ -17,7 +17,7 @@ Name: terragrunt -Version: 0.87.6 +Version: 0.87.7 Release: 0 Summary: Thin wrapper for Terraform for working with multiple Terraform modules License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.jNGtaR/_old 2025-09-26 22:26:47.979771462 +0200 +++ /var/tmp/diff_new_pack.jNGtaR/_new 2025-09-26 22:26:47.983771630 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/gruntwork-io/terragrunt</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v0.87.6</param> + <param name="revision">v0.87.7</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.jNGtaR/_old 2025-09-26 22:26:48.007772642 +0200 +++ /var/tmp/diff_new_pack.jNGtaR/_new 2025-09-26 22:26:48.015772980 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/gruntwork-io/terragrunt</param> - <param name="changesrevision">4d373a44ceaa22142884497cc8f02968c2439453</param></service></servicedata> + <param name="changesrevision">522518f2859fa32538f28d6b274851874ca7044f</param></service></servicedata> (No newline at EOF) ++++++ terragrunt-0.87.6.obscpio -> terragrunt-0.87.7.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.87.6/config/config_partial.go new/terragrunt-0.87.7/config/config_partial.go --- old/terragrunt-0.87.6/config/config_partial.go 2025-09-24 22:32:04.000000000 +0200 +++ new/terragrunt-0.87.7/config/config_partial.go 2025-09-25 16:56:12.000000000 +0200 @@ -300,6 +300,8 @@ if err != nil { return nil, err } + + hclCache.Put(ctx, cacheKey, file) } return TerragruntConfigFromPartialConfig(ctx, l, file, include) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/terragrunt-0.87.6/config/config_partial_test.go new/terragrunt-0.87.7/config/config_partial_test.go --- old/terragrunt-0.87.6/config/config_partial_test.go 2025-09-24 22:32:04.000000000 +0200 +++ new/terragrunt-0.87.7/config/config_partial_test.go 2025-09-25 16:56:12.000000000 +0200 @@ -1,9 +1,17 @@ package config_test import ( + "context" + "fmt" + "os" + "path/filepath" + "strconv" "testing" + "time" "github.com/gruntwork-io/terragrunt/config" + "github.com/gruntwork-io/terragrunt/config/hclparse" + "github.com/gruntwork-io/terragrunt/internal/cache" "github.com/gruntwork-io/terragrunt/test/helpers/logger" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -388,3 +396,205 @@ require.NoError(t, err) assert.Len(t, terragruntConfig.Dependencies.Paths, 1) } + +func TestPartialParseSavesToHclCache(t *testing.T) { + t.Parallel() + + // Setup test environment + tmpDir := t.TempDir() + configPath := filepath.Join(tmpDir, "terragrunt.hcl") + configContent := `dependencies { paths = ["../app1"] }` + require.NoError(t, os.WriteFile(configPath, []byte(configContent), 0644)) + + // Get file metadata for cache key generation + fileInfo, err := os.Stat(configPath) + require.NoError(t, err) + + expectedCacheKey := fmt.Sprintf("configPath-%v-modTime-%v", configPath, fileInfo.ModTime().UnixMicro()) + + // Setup cache and context + hclCache := cache.NewCache[*hclparse.File]("test-hcl-cache") + baseCtx := context.WithValue(t.Context(), config.HclCacheContextKey, hclCache) + l := logger.CreateLogger() + parsingContext := config.NewParsingContext(baseCtx, l, mockOptionsForTest(t)).WithDecodeList(config.DependenciesBlock) + + // Verify cache is empty initially + _, found := hclCache.Get(parsingContext, expectedCacheKey) + require.False(t, found, "cache should be empty before parsing") + + // Parse config file (should populate cache) + _, err = config.PartialParseConfigFile(parsingContext, l, configPath, nil) + require.NoError(t, err) + + // Verify file was cached + cachedFile, found := hclCache.Get(parsingContext, expectedCacheKey) + require.True(t, found, "expected file to be in cache after first parse") + require.NotNil(t, cachedFile, "cached file should not be nil") + + // Verify cached content matches the original + assert.Equal(t, configPath, cachedFile.ConfigPath) + assert.Contains(t, cachedFile.Content(), "dependencies") +} + +func TestPartialParseCacheHitOnSecondParse(t *testing.T) { + t.Parallel() + + tmpDir := t.TempDir() + configPath := filepath.Join(tmpDir, "terragrunt.hcl") + configContent := `dependencies { paths = ["../app1"] }` + require.NoError(t, os.WriteFile(configPath, []byte(configContent), 0644)) + + fileInfo, err := os.Stat(configPath) + require.NoError(t, err) + + cacheKey := fmt.Sprintf("configPath-%v-modTime-%v", configPath, fileInfo.ModTime().UnixMicro()) + + hclCache := cache.NewCache[*hclparse.File]("test-hcl-cache") + baseCtx := context.WithValue(t.Context(), config.HclCacheContextKey, hclCache) + l := logger.CreateLogger() + parsingContext := config.NewParsingContext(baseCtx, l, mockOptionsForTest(t)).WithDecodeList(config.DependenciesBlock) + + // First parse - should be cache miss + _, err = config.PartialParseConfigFile(parsingContext, l, configPath, nil) + require.NoError(t, err) + + // Verify cache hit on second parse + _, err = config.PartialParseConfigFile(parsingContext, l, configPath, nil) + require.NoError(t, err) + + // Verify same file object is returned from cache + cachedFile, found := hclCache.Get(parsingContext, cacheKey) + require.True(t, found) + require.NotNil(t, cachedFile) +} + +func TestPartialParseCacheInvalidationOnFileModification(t *testing.T) { + t.Parallel() + + tmpDir := t.TempDir() + configPath := filepath.Join(tmpDir, "terragrunt.hcl") + originalContent := `dependencies { paths = ["../app1"] }` + modifiedContent := `dependencies { paths = ["../app1", "../app2"] }` + + require.NoError(t, os.WriteFile(configPath, []byte(originalContent), 0644)) + + fileInfo, err := os.Stat(configPath) + require.NoError(t, err) + + originalCacheKey := fmt.Sprintf("configPath-%v-modTime-%v", configPath, fileInfo.ModTime().UnixMicro()) + + hclCache := cache.NewCache[*hclparse.File]("test-hcl-cache") + baseCtx := context.WithValue(t.Context(), config.HclCacheContextKey, hclCache) + l := logger.CreateLogger() + parsingContext := config.NewParsingContext(baseCtx, l, mockOptionsForTest(t)).WithDecodeList(config.DependenciesBlock) + + // Parse original file + _, err = config.PartialParseConfigFile(parsingContext, l, configPath, nil) + require.NoError(t, err) + + // Verify original file is cached + _, found := hclCache.Get(parsingContext, originalCacheKey) + require.True(t, found, "original file should be cached") + + // Modify file (this changes mod time) + require.NoError(t, os.WriteFile(configPath, []byte(modifiedContent), 0644)) + forceModTimeChange(t, configPath, fileInfo.ModTime()) + + // Parse modified file - should create new cache entry + _, err = config.PartialParseConfigFile(parsingContext, l, configPath, nil) + require.NoError(t, err) + + // Verify old cache entry is still there but new one exists + _, found = hclCache.Get(parsingContext, originalCacheKey) + require.True(t, found, "original cache entry should still exist") + + // Get new cache key + fileInfo, err = os.Stat(configPath) + require.NoError(t, err) + + newCacheKey := fmt.Sprintf("configPath-%v-modTime-%v", configPath, fileInfo.ModTime().UnixMicro()) + + // Verify new file is cached with different content + newCachedFile, found := hclCache.Get(parsingContext, newCacheKey) + require.True(t, found, "modified file should be cached") + require.NotNil(t, newCachedFile) + assert.Contains(t, newCachedFile.Content(), "../app2") +} + +func TestPartialParseCacheWithInvalidFile(t *testing.T) { + t.Parallel() + + tmpDir := t.TempDir() + configPath := filepath.Join(tmpDir, "terragrunt.hcl") + invalidContent := `invalid hcl syntax {` + require.NoError(t, os.WriteFile(configPath, []byte(invalidContent), 0644)) + + hclCache := cache.NewCache[*hclparse.File]("test-hcl-cache") + baseCtx := context.WithValue(t.Context(), config.HclCacheContextKey, hclCache) + l := logger.CreateLogger() + parsingContext := config.NewParsingContext(baseCtx, l, mockOptionsForTest(t)).WithDecodeList(config.DependenciesBlock) + + // Parse should fail and not cache an invalid file + _, err := config.PartialParseConfigFile(parsingContext, l, configPath, nil) + require.Error(t, err, "parsing invalid HCL should fail") + + // Verify nothing was cached + fileInfo, err := os.Stat(configPath) + require.NoError(t, err) + + cacheKey := fmt.Sprintf("configPath-%v-modTime-%v", configPath, fileInfo.ModTime().UnixMicro()) + + _, found := hclCache.Get(parsingContext, cacheKey) + require.False(t, found, "invalid file should not be cached") +} + +func TestPartialParseCacheKeyFormat(t *testing.T) { + t.Parallel() + + tmpDir := t.TempDir() + configPath := filepath.Join(tmpDir, "terragrunt.hcl") + configContent := `dependencies { paths = ["../app1"] }` + require.NoError(t, os.WriteFile(configPath, []byte(configContent), 0644)) + + fileInfo, err := os.Stat(configPath) + require.NoError(t, err) + + expectedCacheKey := fmt.Sprintf("configPath-%v-modTime-%v", configPath, fileInfo.ModTime().UnixMicro()) + + hclCache := cache.NewCache[*hclparse.File]("test-hcl-cache") + baseCtx := context.WithValue(t.Context(), config.HclCacheContextKey, hclCache) + l := logger.CreateLogger() + parsingContext := config.NewParsingContext(baseCtx, l, mockOptionsForTest(t)).WithDecodeList(config.DependenciesBlock) + + _, err = config.PartialParseConfigFile(parsingContext, l, configPath, nil) + require.NoError(t, err) + + // Verify cache key format matches the expected pattern + assert.Regexp(t, `^configPath-.*-modTime-\d+$`, expectedCacheKey, "cache key should match expected format") + assert.Contains(t, expectedCacheKey, configPath, "cache key should contain config path") + assert.Contains(t, expectedCacheKey, strconv.FormatInt(fileInfo.ModTime().UnixMicro(), 10), "cache key should contain mod time") + + // Verify we can retrieve using the expected key + _, found := hclCache.Get(parsingContext, expectedCacheKey) + require.True(t, found, "should be able to retrieve using expected cache key format") +} + +// forceModTimeChange ensures the file at path has a modification time strictly after prev. +func forceModTimeChange(t *testing.T, path string, prev time.Time) { + t.Helper() + + deadline := time.Now().Add(5 * time.Second) + for time.Now().Before(deadline) { + err := os.Chtimes(path, time.Now(), time.Now()) + + require.NoError(t, err) + + if fileInfo, err := os.Stat(path); err == nil && fileInfo.ModTime().After(prev) { + return + } + + time.Sleep(1 * time.Millisecond) + } + + t.Fatalf("Failed to change modification time of %s within 5 seconds", path) +} ++++++ terragrunt.obsinfo ++++++ --- /var/tmp/diff_new_pack.jNGtaR/_old 2025-09-26 22:26:52.231950793 +0200 +++ /var/tmp/diff_new_pack.jNGtaR/_new 2025-09-26 22:26:52.235950962 +0200 @@ -1,5 +1,5 @@ name: terragrunt -version: 0.87.6 -mtime: 1758745924 -commit: 4d373a44ceaa22142884497cc8f02968c2439453 +version: 0.87.7 +mtime: 1758812172 +commit: 522518f2859fa32538f28d6b274851874ca7044f ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/terragrunt/vendor.tar.gz /work/SRC/openSUSE:Factory/.terragrunt.new.11973/vendor.tar.gz differ: char 13, line 1
