Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
bb3777e
initial flattenerGeneration test with secretmanager.Secret
BBBmau Feb 6, 2026
1c273c7
Decoder generation in flattenerResource test with kms.cryptoKeys
BBBmau Feb 6, 2026
494b9a0
PostRead + NestedQuery in flattenerResource - accesscontextmanager.Se…
BBBmau Feb 6, 2026
b573d46
bigquery: flattenResource in dataset
BBBmau Feb 9, 2026
f8c0498
add flatten_all_in_method on all resources that have a custom_code.de…
BBBmau Feb 19, 2026
1a77222
remove spanner.Instance and spanner.InstanceConfig - flatteners clash
BBBmau Feb 19, 2026
acb64eb
conflict fixe
BBBmau Feb 21, 2026
d38f802
revert yamls that got extra updates
BBBmau Feb 21, 2026
96900e7
DomainMapping revert
BBBmau Feb 21, 2026
2d22d12
remove tgc_include_handwritten_tests
BBBmau Feb 21, 2026
a653f2f
reduce the flatten_in_all_method in decoders to half
BBBmau Feb 23, 2026
9dafa16
remove flatten_all on resources producing a interaction not found error
BBBmau Feb 23, 2026
1709e16
remove flatten_all_method from cryptoKey
BBBmau Feb 24, 2026
ae1ec0d
remove flatten_all_method from keyRing
BBBmau Feb 24, 2026
cad8f60
Revert "remove flatten_all on resources producing a interaction not f…
BBBmau Feb 25, 2026
4bbdfe0
resolve post merge conflicts
BBBmau Apr 7, 2026
8e88823
enable flatten_all_in_method on Decoder+HasSelfLink+FlattenObject res…
BBBmau Apr 7, 2026
780d7cf
enable flatten_all_in_method on Decoder+HasSelfLink resources
BBBmau Apr 7, 2026
b288b3c
enable flatten_all_in_method on Decoder+NestedQuery resources
BBBmau Apr 7, 2026
cbeae2e
enable flatten_all_in_method on PostRead+NestedQuery resources
BBBmau Apr 7, 2026
e47af8e
enable flatten_all_in_method on Decoder+PostRead+HasSelfLink resources
BBBmau Apr 7, 2026
f3cfbf9
enable flatten_all_in_method on Decoder+PostRead resources
BBBmau Apr 7, 2026
8eadcbd
enable flatten_all_in_method on Decoder+FlattenObject resources
BBBmau Apr 7, 2026
6bd6fd5
enable flatten_all_in_method on remaining decoder-only resources
BBBmau Apr 7, 2026
eb74550
flatten{{resourceName}}Resource signature in resource.go.tmpl
BBBmau Apr 8, 2026
ed75e3a
default run of flattenAllInResource
BBBmau Apr 8, 2026
1e33473
cleanup after merge-conflict resolution
BBBmau Apr 8, 2026
d4ee95a
resolve diffs from rebase to magic-modules/main
BBBmau Apr 21, 2026
69d0921
add Get default provider values in list_metadata.go
BBBmau Apr 8, 2026
4eb8f08
move identity set logic to its own SetIdentityFields method
BBBmau Apr 9, 2026
7c0db64
initial run generation WIP
BBBmau Dec 5, 2025
778153e
move generation of list resource to be its own file instead of within…
BBBmau Dec 9, 2025
978d3c2
pseudocode list_resource
BBBmau Dec 13, 2025
6579a8c
WIP
BBBmau Dec 16, 2025
352b073
initial list_resource generation support - no standarized iterator (N…
BBBmau Dec 4, 2025
88c6ead
resolve build errors
BBBmau Apr 9, 2026
bd659cf
refactor to use flattenResource method generated from mau/flattenReso…
BBBmau Apr 9, 2026
e8e8ae8
major refactoring
BBBmau Apr 10, 2026
686b598
remove cloud_clients.go.tmpl
BBBmau Apr 10, 2026
34bd387
include gneerated list resources in framework_mmv1
BBBmau Apr 10, 2026
27fe65e
first successful run of tf query on generated list resource (cloud_ru…
BBBmau Apr 10, 2026
ef852e8
fix name being empty in list query results
BBBmau Apr 10, 2026
8eb84a6
refactor to handle setResult + setIdentity in list_resource metadata …
BBBmau Apr 10, 2026
3414586
refactor to handle Configure / Metadata / RawV5Schemas in in list_res…
BBBmau Apr 10, 2026
de3404d
add ListScopeProperties for values from base_url string
BBBmau Apr 10, 2026
7a50998
remove filter field from list resource generation
BBBmau Apr 10, 2026
d4f9e64
split list_resource.go.tmpl into multiple templates
BBBmau Apr 10, 2026
c492c9d
migrate to framework_mmv1_resources template
BBBmau Apr 21, 2026
b74540b
remove duplicate definitions after rebase
BBBmau Apr 21, 2026
74c2766
update to use ListPagesOptions struct
BBBmau Apr 21, 2026
2aa8b8e
match list_utils changes introduced in upstream magic-modules
BBBmau Apr 21, 2026
abad659
refactors to allow for reuse of resourceFlattener in list resources +…
BBBmau Apr 21, 2026
fcbbe70
remove common~copy changes
BBBmau Apr 21, 2026
56a6d85
more common~copy removals
BBBmau Apr 21, 2026
0a26a14
remove what is unnecessary
BBBmau Apr 21, 2026
f6cf811
ListResultDisplayName for setting DisplayName of resource in query re…
BBBmau Apr 21, 2026
8405492
initial query test generation implementation
BBBmau Apr 21, 2026
e4097e9
simpler flattener gen
BBBmau Apr 21, 2026
4e097d3
add settable_propeorties that are only set on create
BBBmau Apr 22, 2026
2ed4fd6
remove unused existsInBaseUrl
BBBmau Apr 22, 2026
5e63bc7
simplify ResourceFlattener call in list_resource_method.go.tmpl
BBBmau Apr 23, 2026
e17679b
remove comments
BBBmau Apr 23, 2026
85b0e9c
simplify case where the res can be a TypeInt but res returns string
BBBmau Apr 23, 2026
52af40c
simplify getGeneratedListResoucesInVersion
BBBmau Apr 23, 2026
dccd3be
more robust ListResultDsiplayNameKeyStrings method
BBBmau Apr 23, 2026
dd97142
simplify ListScopeProperties
BBBmau Apr 23, 2026
a782d73
remove HasLocation method
BBBmau Apr 23, 2026
3c19d8e
cleanup service.yaml
BBBmau Apr 23, 2026
cdf96f8
more
BBBmau Apr 23, 2026
3e46864
refactors in templates
BBBmau Apr 23, 2026
01bc236
simplify query_test_gen
BBBmau Apr 23, 2026
7f61926
fixes on query test gen + passing run for cloudrun service query
BBBmau Apr 23, 2026
d5947ad
revert refactor
BBBmau Apr 23, 2026
29a93a4
remove more
BBBmau Apr 23, 2026
4ae54ca
improved testing on ResourceDisplayName
BBBmau Apr 23, 2026
67f2b06
rename of generated files for list
BBBmau Apr 23, 2026
6fb51c7
move Decoder, NestedQuery, and PostRead in list_resource__method.go.tmpl
BBBmau Apr 27, 2026
2bff1ca
use bootstrapProjects for query_test generation
BBBmau Apr 27, 2026
7f29083
add list_query_test_utils for explicit checking of DisplayName for pr…
BBBmau Apr 28, 2026
02bd1f7
move list test utils to test_utils.go.tmpl
BBBmau Apr 29, 2026
3468e8c
storage bucket testing + refining testing for non variable update
BBBmau Apr 30, 2026
a44b4d1
remove project_service
BBBmau Apr 30, 2026
4976a18
add conditional for setting optional true or false for list schemas
BBBmau Apr 30, 2026
c8984ef
add itemName fallback for default collection_key_url useage
BBBmau Apr 30, 2026
3bfbd15
include registry init for list resources in list_resource.go.tmpl
BBBmau May 4, 2026
82a69cb
remove registration of list_resources in favor of registry init
BBBmau May 4, 2026
1d1cdb9
remove generate_list_resource for cloudbuild and trigger
BBBmau May 4, 2026
69a5b62
more cleanups in list_resource_method - remove meta interface{} set
BBBmau May 4, 2026
0164775
move billingProject set in hasProject
BBBmau May 4, 2026
a84e022
minimize error messages
BBBmau May 4, 2026
26eae63
more cleanups
BBBmau May 4, 2026
4bc9ab9
add importPath for registry import
BBBmau May 4, 2026
db2d496
use slics.ContainsFunc in DisplayNameKeyStrings helper method
BBBmau May 4, 2026
a300a51
use hasEligibleExample method in listResourceQueryTest generation
BBBmau May 5, 2026
e12d36c
combine example check as one
BBBmau May 5, 2026
99bd825
match main
BBBmau May 5, 2026
82a7deb
move list generation to within generateResource
BBBmau May 5, 2026
7f54ccc
remove emptyline
BBBmau May 5, 2026
59a3fc6
documentation generation for list-resources
BBBmau May 5, 2026
7435c84
MIGRATION: query_test.go.tmpl uses samples
BBBmau May 6, 2026
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
21 changes: 21 additions & 0 deletions mmv1/api/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ type Resource struct {
// EXPERIMENTAL: If true, resource should be autogenerated as a data source
Datasource *resource.Datasource `yaml:"datasource_experimental,omitempty"`

GenerateListResource bool `yaml:"generate_list_resource,omitempty"`

// If true, skip sweeper generation for this resource
ExcludeSweeper bool `yaml:"exclude_sweeper,omitempty"`

Expand Down Expand Up @@ -715,6 +717,25 @@ func (r Resource) IdentityProperties() []*Type {
return props
}

func (r Resource) ListScopeProperties() []*Type {
scope := r.ExtractIdentifiers(r.CollectionUrl())
return google.Select(r.IdentityProperties(), func(p *Type) bool {
return slices.Contains(scope, google.Underscore(p.Name))
})
}

func (r Resource) ListResultDisplayNameKeyStrings() []string {
var keys []string
if slices.ContainsFunc(r.RootProperties(), func(p *Type) bool { return p.Name == "display_name" }) {
keys = append(keys, "display_name")
}
markers := regexp.MustCompile(`\{\{(\w+)\}\}`).FindAllStringSubmatch(r.IdFormat, -1)
if len(markers) > 0 {
keys = append(keys, markers[len(markers)-1][1])
}
return keys
}

func (r Resource) SensitiveProps() []*Type {
props := r.AllNestedProperties(r.RootProperties())
return google.Select(props, func(p *Type) bool {
Expand Down
1 change: 1 addition & 0 deletions mmv1/products/cloudrun/Service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import_format:
datasource_experimental:
generate: true
exclude_test: true
generate_list_resource: true
timeouts:
insert_minutes: 20
update_minutes: 20
Expand Down
18 changes: 18 additions & 0 deletions mmv1/provider/template_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ func (td *TemplateData) GenerateDocumentationFile(filePath string, resource api.
td.GenerateFile(filePath, templatePath, resource, false, templates...)
}

func (td *TemplateData) GenerateListResourceDocumentationFile(filePath string, resource api.Resource) {
templatePath := "templates/terraform/list_resource.html.markdown.tmpl"
templates := []string{
templatePath,
}
td.GenerateFile(filePath, templatePath, resource, false, templates...)
}

func (td *TemplateData) GenerateTestFileLegacy(filePath string, resource api.Resource) {
templatePath := "templates/terraform/examples/base_configs/test_file.go.tmpl"
templates := []string{
Expand Down Expand Up @@ -282,6 +290,16 @@ func (td *TemplateData) GenerateIamPolicyTestFile(filePath string, resource api.
td.GenerateFile(filePath, templatePath, resource, true, templates...)
}

// GenerateQueryTestFile emits a Terraform query-mode acceptance test for list resources (generate_list_resource).
func (td *TemplateData) GenerateQueryTestFile(filePath string, resource api.Resource) {
templatePath := "templates/terraform/samples/base_configs/query_test_file.go.tmpl"
templates := []string{
templatePath,
"templates/terraform/env_var_context.go.tmpl",
}
td.GenerateFile(filePath, templatePath, resource, true, templates...)
}

func (td *TemplateData) GenerateSweeperFile(filePath string, resource api.Resource) {
templatePath := "templates/terraform/sweeper_file.go.tmpl"
templates := []string{
Expand Down
37 changes: 37 additions & 0 deletions mmv1/provider/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,38 @@ func (t *Terraform) GenerateResource(object api.Resource, templateData TemplateD
targetFilePath := path.Join(targetFolder, fmt.Sprintf("resource_%s.go", t.ResourceGoFilename(object)))
templateData.GenerateResourceFile(targetFilePath, object)
}

t.GenerateListResource(object, templateData, targetFolder)
}

if generateDocs {
targetFolder := t.makeFolder(outputFolder, "website", "docs", "r")
targetFilePath := path.Join(targetFolder, fmt.Sprintf("%s.html.markdown", t.FullResourceName(object)))
templateData.GenerateDocumentationFile(targetFilePath, object)

if object.GenerateListResource {
listDocFolder := t.makeFolder(outputFolder, "website", "docs", "list-resources")
listDocFilePath := path.Join(listDocFolder, fmt.Sprintf("%s.html.markdown", object.TerraformName()))
templateData.GenerateListResourceDocumentationFile(listDocFilePath, object)
}
}
}

func (t *Terraform) GenerateListResource(object api.Resource, templateData TemplateData, targetFolder string) {
if object.GenerateListResource {
if object.ExcludeIdentityGeneration {
log.Fatalf("generate_list_resource requires identity support; remove exclude_identity_generation from resource %q or disable generate_list_resource", object.Name)
}
if object.ExcludeRead {
log.Fatalf("generate_list_resource requires read support; remove exclude_read from resource %q or disable generate_list_resource", object.Name)
}
targetFilePath := path.Join(targetFolder, fmt.Sprintf("list_%s.go", t.ResourceGoFilename(object)))
templateData.GenerateFile(targetFilePath, "templates/terraform/list_resource.go.tmpl", object, true,
"templates/terraform/list_resource.go.tmpl",
"templates/terraform/list_resource_method.go.tmpl",
)

t.GenerateListResourceQueryTest(object, templateData, targetFolder)
}
}

Expand Down Expand Up @@ -249,6 +275,17 @@ func (t *Terraform) GenerateResourceTests(object api.Resource, templateData Temp
templateData.GenerateTestFile(targetFilePath, object)
}

func (t *Terraform) GenerateListResourceQueryTest(object api.Resource, templateData TemplateData, targetFolder string) {
if object.Samples != nil && object.Examples != nil {
log.Fatalf("Both Samples and Examples block exist in %v", object.Name)
}
if object.Samples == nil || !t.hasEligibleSample(object) {
return
}
targetFilePath := path.Join(targetFolder, fmt.Sprintf("list_%s_generated_test.go", t.ResourceGoFilename(object)))
templateData.GenerateQueryTestFile(targetFilePath, object)
}

func (t *Terraform) GenerateResourceSweeper(object api.Resource, templateData TemplateData, outputFolder string) {
if !object.ShouldGenerateSweepers() {
return
Expand Down
124 changes: 124 additions & 0 deletions mmv1/templates/terraform/list_resource.go.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{{/* The license inside this block applies to this file
Copyright 2024 Google LLC. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */ -}}
// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: MPL-2.0

{{$.CodeHeader TemplatePath}}

package {{ lower $.ProductMetadata.Name }}

import (
"context"
"errors"
"fmt"
"net/http"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/list"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"

"{{ $.ImportPath }}/registry"
"{{ $.ImportPath }}/tpgresource"
transport_tpg "{{ $.ImportPath }}/transport"
)

func init() {
registry.FrameworkListResource{
Name: "{{ $.TerraformName }}",
ProductName: "{{ $.ProductMetadata.Name }}",
Func: New{{ $.ResourceName -}}ListResource,
}.Register()
}

var _ list.ListResource = &{{ $.ResourceName -}}ListResource{}

type {{ $.ResourceName -}}ListResource struct {
tpgresource.ListResourceMetadata
}

func New{{ $.ResourceName -}}ListResource() list.ListResource {
listR := &{{ $.ResourceName -}}ListResource{}
listR.TypeName = "{{ $.TerraformName }}"
listR.SDKv2Resource = Resource{{ $.ResourceName -}}()
listR.ListConfigFields = []tpgresource.ListConfigField{
{{- range $scope := $.ListScopeProperties }}
{Name: "{{ underscore $scope.Name }}", Kind: tpgresource.ListConfigKindString, Optional: {{ if $scope.Required }}false{{ else }}true{{ end }}},
{{- end }}
}
return listR
}

// {{ $.ResourceName }}ListModel matches ListResourceMetadata.ListConfigFields (tfsdk names and types).
type {{ $.ResourceName -}}ListModel struct {
{{- range $scope := $.ListScopeProperties }}
{{ $scope.TitlelizeProperty }} types.String `tfsdk:"{{ underscore $scope.Name }}"`
{{- end }}
}

func (listR *{{ $.ResourceName -}}ListResource) List(ctx context.Context, listReq list.ListRequest, stream *list.ListResultsStream) {
var data {{ $.ResourceName -}}ListModel
diags := listReq.Config.Get(ctx, &data)
if diags.HasError() {
stream.Results = list.ListResultsStreamDiagnostics(diags)
return
}
if listR.Client == nil {
diags = append(diags, diag.NewErrorDiagnostic(
"Provider not configured",
"The Google provider client is not available; ensure the provider is configured (e.g. credentials and default project).",
))
stream.Results = list.ListResultsStreamDiagnostics(diags)
return
}

{{- range $scope := $.ListScopeProperties }}
{{- if or (eq $scope.Name "project") (eq $scope.Name "region") (eq $scope.Name "zone") (eq $scope.Name "location") }}
{{ $scope.CamelizeProperty }} := listR.Get{{ $scope.TitlelizeProperty }}(data.{{ $scope.TitlelizeProperty }})
{{- else }}
{{ $scope.CamelizeProperty }} := data.{{ $scope.TitlelizeProperty }}.ValueString()
{{- end }}
{{- end }}

stream.Results = func(push func(list.ListResult) bool) {
err := List{{ $.ResourceName }}s(
listR.Client,
{{- range $scope := $.ListScopeProperties }}
{{ $scope.CamelizeProperty }},
{{- end }}
func(rd *schema.ResourceData) error {
result := listReq.NewListResult(ctx)

if err := listR.SetResult(ctx, listReq.IncludeResource, &result, rd{{- range $k := $.ListResultDisplayNameKeyStrings }}, "{{ $k }}"{{- end }}); err != nil {
return err
}

if !push(result) {
return errors.New("stream closed")
}
return nil
},
)
if err != nil {
diags.AddError("API Error", err.Error())
result := listReq.NewListResult(ctx)
result.Diagnostics = diags
push(result)
}
}
}

{{ template "listResourceMethod" $ }}
54 changes: 54 additions & 0 deletions mmv1/templates/terraform/list_resource.html.markdown.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{{- /* Copyright 2024 Google LLC. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */ -}}
---
{{$.MarkdownHeader TemplatePath}}
subcategory: "{{$.ProductMetadata.DisplayName}}"
description: |-
List {{$.ProductMetadata.DisplayName}} {{lower $.Name}} resources in a project for use with terraform query
and .tfquery.hcl files.
---

# {{$.TerraformName}} (list)

Lists [`{{$.TerraformName}}`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/{{$.TerraformName}}) resources for use with [`terraform query`](https://developer.hashicorp.com/terraform/cli/commands/query) and **`.tfquery.hcl`** files.

For how list resources work in this provider, file layout, Terraform version requirements, and shared `list` block arguments, refer to the guide [Use list resources with terraform query (Google Cloud provider)](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/using_list_resources_with_terraform_query).

## Example

```hcl
list "{{$.TerraformName}}" "all" {
provider = {{ if eq $.MinVersion "beta" }}google-beta{{ else }}google{{ end }}

config {
{{- range $scope := $.ListScopeProperties }}
{{ underscore $scope.Name }} = {{ if $scope.Required }}"..."{{ else }}"..." # Optional{{ end }}
{{- end }}
}
}
```

Run `terraform query` from the directory that contains the `.tfquery.hcl` file.

## Configuration (`config` block)

{{- range $scope := $.ListScopeProperties }}
* `{{ underscore $scope.Name }}` - ({{ if $scope.Required }}Required{{ else }}Optional{{ end }}){{ if $scope.Description }} {{ $scope.Description }}{{ end }}
{{- end }}

## Results

By default each result includes **resource identity** for [`{{$.TerraformName}}`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/{{$.TerraformName}}) (see [Resource identity](https://developer.hashicorp.com/terraform/language/resources/identities)).

With `include_resource = true` on the `list` block, results also include the full resource-style attributes documented for the managed [`{{$.TerraformName}}` resource](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/{{$.TerraformName}}#attributes-reference).
Loading
Loading