diff --git a/internal/command/meta_dependencies.go b/internal/command/meta_dependencies.go index b84afecf3a..c60c9f5464 100644 --- a/internal/command/meta_dependencies.go +++ b/internal/command/meta_dependencies.go @@ -79,10 +79,20 @@ func (m *Meta) replaceLockedDependencies(new *depsfile.Locks) tfdiags.Diagnostic // This method supports downloading providers in 2 steps, and is used during the second download step and // while updating the dependency lock file. func (m *Meta) mergeLockedDependencies(baseLocks, additionalLocks *depsfile.Locks) *depsfile.Locks { + if baseLocks == nil && additionalLocks == nil { + return depsfile.NewLocks() // empty locks + } + if additionalLocks == nil { + return baseLocks + } + if baseLocks == nil { + return additionalLocks + } - mergedLocks := baseLocks.DeepCopy() + // Here we know that there are two sets of locks to combine and return // Append locks derived from the state to locks derived from config. + mergedLocks := baseLocks.DeepCopy() for _, lock := range additionalLocks.AllProviders() { match := mergedLocks.Provider(lock.Provider()) if match != nil { diff --git a/internal/command/meta_dependencies_test.go b/internal/command/meta_dependencies_test.go index b245648867..0bc02996ff 100644 --- a/internal/command/meta_dependencies_test.go +++ b/internal/command/meta_dependencies_test.go @@ -17,7 +17,6 @@ import ( // This tests combining locks from config and state. Locks derived from state are always unconstrained, i.e. no version constraint data, // so this test func Test_mergeLockedDependencies_config_and_state(t *testing.T) { - providerA := tfaddr.NewProvider(tfaddr.DefaultProviderRegistryHost, "my-org", "providerA") providerB := tfaddr.NewProvider(tfaddr.DefaultProviderRegistryHost, "my-org", "providerB") v1_0_0 := providerreqs.MustParseVersion("1.0.0") @@ -38,6 +37,37 @@ func Test_mergeLockedDependencies_config_and_state(t *testing.T) { stateLocks: depsfile.NewLocks(), expectedLocks: depsfile.NewLocks(), }, + "nil config locks": { + configLocks: nil, + stateLocks: func() *depsfile.Locks { + configLocks := depsfile.NewLocks() + configLocks.SetProvider(providerA, v1_0_0, versionConstraintv1, hashesProviderA) + return configLocks + }(), + expectedLocks: func() *depsfile.Locks { + combinedLocks := depsfile.NewLocks() + combinedLocks.SetProvider(providerA, v1_0_0, versionConstraintv1, hashesProviderA) + return combinedLocks + }(), + }, + "nil state locks": { + configLocks: func() *depsfile.Locks { + configLocks := depsfile.NewLocks() + configLocks.SetProvider(providerA, v1_0_0, versionConstraintv1, hashesProviderA) + return configLocks + }(), + stateLocks: nil, + expectedLocks: func() *depsfile.Locks { + combinedLocks := depsfile.NewLocks() + combinedLocks.SetProvider(providerA, v1_0_0, versionConstraintv1, hashesProviderA) + return combinedLocks + }(), + }, + "all nil locks": { + configLocks: nil, + stateLocks: nil, + expectedLocks: depsfile.NewLocks(), + }, "when provider only described in config, output locks have matching constraints": { configLocks: func() *depsfile.Locks { configLocks := depsfile.NewLocks()