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

Copy lock file only when needed #2823

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
45 changes: 39 additions & 6 deletions util/file.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package util

import (
"bytes"
"encoding/gob"
"io"
"os"
Expand Down Expand Up @@ -584,15 +585,47 @@ func (err PathIsNotFile) Error() string {
// Terraform 0.14 now generates a lock file when you run `terraform init`.
// If any such file exists, this function will copy the lock file to the destination folder
func CopyLockFile(sourceFolder string, destinationFolder string, logger *logrus.Entry) error {
sourceLockFilePath := JoinPath(sourceFolder, TerraformLockFile)
destinationLockFilePath := JoinPath(destinationFolder, TerraformLockFile)
sourceLockFilePath, sourceErr := filepath.Abs(JoinPath(sourceFolder, TerraformLockFile))
if sourceErr != nil {
return errors.WithStackTrace(sourceErr)
}
destinationLockFilePath, destErr := filepath.Abs(JoinPath(destinationFolder, TerraformLockFile))
if destErr != nil {
return errors.WithStackTrace(destErr)
}

if FileExists(sourceLockFilePath) {
logger.Debugf("Copying lock file from %s to %s", sourceLockFilePath, destinationFolder)
return CopyFile(sourceLockFilePath, destinationLockFilePath)
if sourceLockFilePath == destinationLockFilePath {
logger.Debugf("Source and destination lock file paths are the same: %s. Not copying.", sourceLockFilePath)
return nil
}

return nil
if !FileExists(sourceLockFilePath) {
logger.Debugf("Source lock file does not exist: %s. Not copying.", sourceLockFilePath)
return nil
}

sourceContents, sourceReadErr := os.ReadFile(sourceLockFilePath)
if sourceReadErr != nil {
return errors.WithStackTrace(sourceReadErr)
}

if !FileExists(destinationLockFilePath) {
logger.Debugf("Destination lock file does not exist: %s. Copying.", destinationLockFilePath)
return WriteFileWithSamePermissions(sourceLockFilePath, destinationLockFilePath, sourceContents)
}

destinationContents, destReadErr := os.ReadFile(destinationLockFilePath)
if destReadErr != nil {
return errors.WithStackTrace(destReadErr)
}

if bytes.Equal(sourceContents, destinationContents) {
logger.Debugf("Source and destination lock file contents are the same. Not copying.")
return nil
}

logger.Debugf("Copying lock file from %s to %s", sourceLockFilePath, destinationFolder)
return WriteFileWithSamePermissions(sourceLockFilePath, destinationLockFilePath, sourceContents)
}

// ListTfFiles returns a list of all TF files in the specified directory.
Expand Down
114 changes: 114 additions & 0 deletions util/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package util

import (
"errors"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
Expand All @@ -11,6 +13,7 @@ import (
"fmt"

"github.com/gruntwork-io/terragrunt/test/helpers"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -336,5 +339,116 @@ func TestEmptyDir(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, testCase.expectEmpty, emptyValue, "For path %s", testCase.path)
}
}

func TestCopyLockFile(t *testing.T) {
logger := logrus.New()
logger.Out = io.Discard
loggerEntry := logger.WithFields(logrus.Fields{})

t.Run("SameSourceAndDestination", func(t *testing.T) {
sourceFolder := "/path/to/folder"
destinationFolder := "/path/to/folder"

err := CopyLockFile(sourceFolder, destinationFolder, loggerEntry)
assert.NoError(t, err)
})

t.Run("SourceLockFileDoesNotExist", func(t *testing.T) {
sourceFolder := "/path/to/folder"
destinationFolder := "/path/to/destination"

err := CopyLockFile(sourceFolder, destinationFolder, loggerEntry)
assert.NoError(t, err)
})

t.Run("DestinationLockFileDoesNotExist", func(t *testing.T) {
sourceFolder := t.TempDir()
destinationFolder := t.TempDir()

sourceLockFilePath := filepath.Join(sourceFolder, TerraformLockFile)
destinationLockFilePath := filepath.Join(destinationFolder, TerraformLockFile)

// Create source lock file
err := ioutil.WriteFile(sourceLockFilePath, []byte("lock file contents"), 0644)
require.NoError(t, err)

err = CopyLockFile(sourceFolder, destinationFolder, loggerEntry)
assert.NoError(t, err)

// Verify destination lock file exists
_, err = os.Stat(destinationLockFilePath)
assert.NoError(t, err)

// Verify destination lock file contents
destinationContents, err := ioutil.ReadFile(destinationLockFilePath)
assert.NoError(t, err)
assert.Equal(t, []byte("lock file contents"), destinationContents)

// Clean up
err = os.Remove(sourceLockFilePath)
assert.NoError(t, err)
err = os.Remove(destinationLockFilePath)
assert.NoError(t, err)
})

t.Run("SameContents", func(t *testing.T) {
sourceFolder := t.TempDir()
destinationFolder := t.TempDir()

sourceLockFilePath := filepath.Join(sourceFolder, TerraformLockFile)
destinationLockFilePath := filepath.Join(destinationFolder, TerraformLockFile)

// Create source lock file
err := ioutil.WriteFile(sourceLockFilePath, []byte("lock file contents"), 0644)
require.NoError(t, err)

// Create destination lock file with same contents
err = ioutil.WriteFile(destinationLockFilePath, []byte("lock file contents"), 0644)
require.NoError(t, err)

err = CopyLockFile(sourceFolder, destinationFolder, loggerEntry)
assert.NoError(t, err)

// Verify destination lock file contents remain the same
destinationContents, err := ioutil.ReadFile(destinationLockFilePath)
assert.NoError(t, err)
assert.Equal(t, []byte("lock file contents"), destinationContents)

// Clean up
err = os.Remove(sourceLockFilePath)
assert.NoError(t, err)
err = os.Remove(destinationLockFilePath)
assert.NoError(t, err)
})

t.Run("DifferentContents", func(t *testing.T) {
sourceFolder := t.TempDir()
destinationFolder := t.TempDir()

sourceLockFilePath := filepath.Join(sourceFolder, TerraformLockFile)
destinationLockFilePath := filepath.Join(destinationFolder, TerraformLockFile)

// Create source lock file
err := ioutil.WriteFile(sourceLockFilePath, []byte("lock file contents"), 0644)
require.NoError(t, err)

// Create destination lock file with different contents
err = ioutil.WriteFile(destinationLockFilePath, []byte("different contents"), 0644)
require.NoError(t, err)

err = CopyLockFile(sourceFolder, destinationFolder, loggerEntry)
assert.NoError(t, err)

// Verify destination lock file contents are updated
destinationContents, err := ioutil.ReadFile(destinationLockFilePath)
assert.NoError(t, err)
assert.Equal(t, []byte("lock file contents"), destinationContents)

// Clean up
err = os.Remove(sourceLockFilePath)
assert.NoError(t, err)
err = os.Remove(destinationLockFilePath)
assert.NoError(t, err)
})
}