command: Providers schema shows required_providers

The providers schema command is using the Config.ProviderTypes method,
which had not been kept up to date with the changes to provider
requirements detection made in Config.ProviderRequirements. This
resulted in any currently-unused providers being omitted from the
output.

This commit changes the ProviderTypes method to use the same underlying
logic as ProviderRequirements, which ensures that `required_providers`
blocks are taken into account.

Includes an integration test case to verify that this fixes the provider
schemas command bug.
This commit is contained in:
Alisdair McDiarmid 2020-09-21 16:32:50 -04:00
parent 915d4e4b45
commit 18f9ea53b9
5 changed files with 89 additions and 55 deletions

View File

@ -0,0 +1,41 @@
{
"format_version": "0.1",
"provider_schemas": {
"registry.terraform.io/hashicorp/test": {
"provider": {
"version": 0,
"block": {
"attributes": {
"region": {
"description_kind": "plain",
"optional": true,
"type": "string"
}
},
"description_kind": "plain"
}
},
"resource_schemas": {
"test_instance": {
"version": 0,
"block": {
"attributes": {
"ami": {
"type": "string",
"optional": true,
"description_kind": "plain"
},
"id": {
"type": "string",
"optional": true,
"computed": true,
"description_kind": "plain"
}
},
"description_kind": "plain"
}
}
}
}
}
}

View File

@ -0,0 +1,7 @@
terraform {
required_providers {
test = {
source = "hashicorp/test"
}
}
}

View File

@ -226,6 +226,7 @@ func (c *Config) addProviderRequirements(reqs getproviders.Requirements, recurse
var diags hcl.Diagnostics
// First we'll deal with the requirements directly in _our_ module...
if c.Module.ProviderRequirements != nil {
for _, providerReqs := range c.Module.ProviderRequirements.RequiredProviders {
fqn := providerReqs.Type
if _, ok := reqs[fqn]; !ok {
@ -253,6 +254,8 @@ func (c *Config) addProviderRequirements(reqs getproviders.Requirements, recurse
}
reqs[fqn] = append(reqs[fqn], constraints...)
}
}
// Each resource in the configuration creates an *implicit* provider
// dependency, though we'll only record it if there isn't already
// an explicit dependency on the same provider.
@ -323,11 +326,11 @@ func (c *Config) addProviderRequirements(reqs getproviders.Requirements, recurse
// provider version selection in an earlier step and have identified suitable
// versions for each provider.
func (c *Config) ProviderTypes() []addrs.Provider {
m := make(map[addrs.Provider]struct{})
c.gatherProviderTypes(m)
// Ignore diagnostics here because they relate to version constraints
reqs, _ := c.ProviderRequirements()
ret := make([]addrs.Provider, 0, len(m))
for k := range m {
ret := make([]addrs.Provider, 0, len(reqs))
for k := range reqs {
ret = append(ret, k)
}
sort.Slice(ret, func(i, j int) bool {
@ -336,32 +339,6 @@ func (c *Config) ProviderTypes() []addrs.Provider {
return ret
}
func (c *Config) gatherProviderTypes(m map[addrs.Provider]struct{}) {
if c == nil {
return
}
for _, pc := range c.Module.ProviderConfigs {
fqn := c.Module.ProviderForLocalConfig(addrs.LocalProviderConfig{LocalName: pc.Name})
m[fqn] = struct{}{}
}
for _, rc := range c.Module.ManagedResources {
providerAddr := rc.ProviderConfigAddr()
fqn := c.Module.ProviderForLocalConfig(providerAddr)
m[fqn] = struct{}{}
}
for _, rc := range c.Module.DataResources {
providerAddr := rc.ProviderConfigAddr()
fqn := c.Module.ProviderForLocalConfig(providerAddr)
m[fqn] = struct{}{}
}
// Must also visit our child modules, recursively.
for _, cc := range c.Children {
cc.gatherProviderTypes(m)
}
}
// ResolveAbsProviderAddr returns the AbsProviderConfig represented by the given
// ProviderConfig address, which must not be nil or this method will panic.
//

View File

@ -32,6 +32,7 @@ func TestConfigProviderTypes(t *testing.T) {
addrs.NewDefaultProvider("aws"),
addrs.NewDefaultProvider("null"),
addrs.NewDefaultProvider("template"),
addrs.NewDefaultProvider("test"),
}
for _, problem := range deep.Equal(got, want) {
t.Error(problem)

View File

@ -13,3 +13,11 @@ resource "aws_instance" "foo" {
resource "null_resource" "foo" {
}
terraform {
required_providers {
test = {
source = "hashicorp/test"
}
}
}