From 1c5d7ec6f0246b8a59682d9a4bc44b133d4c5320 Mon Sep 17 00:00:00 2001 From: Zhenhua Li Date: Fri, 15 Mar 2024 10:31:43 -0700 Subject: [PATCH 1/3] Clean up function all_resourcerefs --- mmv1/api/resource.rb | 43 +------------------------------------------ 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/mmv1/api/resource.rb b/mmv1/api/resource.rb index 7ff67c56035a..beed4a1f3dca 100644 --- a/mmv1/api/resource.rb +++ b/mmv1/api/resource.rb @@ -389,11 +389,6 @@ def all_nested_properties(props) nested end - # Returns all resourcerefs at any depth - def all_resourcerefs - resourcerefs_for_properties(all_user_properties, self) - end - # All settable properties in the resource. # Fingerprints aren't *really" settable properties, but they behave like one. # At Create, they have no value but they can just be read in anyways, and after a Read @@ -770,41 +765,5 @@ def validate_identity if all_user_properties.select { |p| p.name == i }.empty? end end - - # Given an array of properties, return all ResourceRefs contained within - # Requires: - # props- a list of props - # original_object - the original object containing props. This is to - # avoid self-referencing objects. - def resourcerefs_for_properties(props, original_obj) - rrefs = [] - props.each do |p| - # We need to recurse on ResourceRefs to get all levels - # We do not want to recurse on resourcerefs of type self to avoid - # infinite loop. - if p.is_a? Api::Type::ResourceRef - # We want to avoid a circular reference - # This reference may be the next reference or have some number of refs - # in between it. - next if p.resource_ref == original_obj - next if p.resource_ref == p.__resource - - rrefs << p - rrefs.concat(resourcerefs_for_properties(p.resource_ref - .required_properties, - original_obj)) - elsif !p.nested_properties.nil? - rrefs.concat(resourcerefs_for_properties(p.nested_properties, original_obj)) - elsif p.is_a? Api::Type::Array - if p.item_type.is_a? Api::Type::ResourceRef - rrefs << p.item_type - rrefs.concat(resourcerefs_for_properties(p.item_type.resource_ref - .required_properties, - original_obj)) - end - end - end - rrefs.uniq - end end -end +end \ No newline at end of file From 7b5767f90d719d0270e80b4f8e7909252ed04f45 Mon Sep 17 00:00:00 2001 From: Zhenhua Li Date: Fri, 15 Mar 2024 10:32:03 -0700 Subject: [PATCH 2/3] Add slice utility functions --- mmv1/google/slice_utils.go | 41 ++++++++++ mmv1/google/slice_utils_test.go | 138 ++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 mmv1/google/slice_utils.go create mode 100644 mmv1/google/slice_utils_test.go diff --git a/mmv1/google/slice_utils.go b/mmv1/google/slice_utils.go new file mode 100644 index 000000000000..75ad22de3b7d --- /dev/null +++ b/mmv1/google/slice_utils.go @@ -0,0 +1,41 @@ +// Copyright 2024 Google Inc. +// 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. + +package google + +// Returns a new slice containing all of the elements +// for which the test function returns true in the original slice +func Select[T any](S []T, test func(T) bool) (ret []T) { + for _, s := range S { + if test(s) { + ret = append(ret, s) + } + } + return +} + +// Returns a new slice containing all of the elements +// for which the test function returns false in the original slice +func Reject[T any](S []T, test func(T) bool) (ret []T) { + for _, s := range S { + if !test(s) { + ret = append(ret, s) + } + } + return +} + +// Concat two slices +func Concat[T any](S1 []T, S2 []T) (ret []T) { + return append(S1, S2...) +} diff --git a/mmv1/google/slice_utils_test.go b/mmv1/google/slice_utils_test.go new file mode 100644 index 000000000000..98532795f8b0 --- /dev/null +++ b/mmv1/google/slice_utils_test.go @@ -0,0 +1,138 @@ +package google + +import ( + "reflect" + "testing" +) + +func TestSliceSelect(t *testing.T) { + t.Parallel() + + cases := []struct { + description string + S []int + testFun func(int) bool + expected int + }{ + { + description: "interger slice selects even numbers", + S: []int{0, 1, 2}, + testFun: func(n int) bool { + return n%2 == 0 + }, + expected: 2, + }, + { + description: "empty slice", + S: make([]int, 0), + testFun: func(n int) bool { + return n%2 == 0 + }, + expected: 0, + }, + { + description: "nil slice", + S: nil, + testFun: func(n int) bool { + return n%2 == 0 + }, + expected: 0, + }, + } + + for _, tc := range cases { + tc := tc + + t.Run(tc.description, func(t *testing.T) { + t.Parallel() + + if got, want := len(Select(tc.S, tc.testFun)), tc.expected; !reflect.DeepEqual(got, want) { + t.Errorf("expected %v to be %v", got, want) + } + }) + } +} + +func TestSliceReject(t *testing.T) { + t.Parallel() + + cases := []struct { + description string + S []int + testFun func(int) bool + expected int + }{ + { + description: "interger slice rejects even numbers", + S: []int{0, 1, 2}, + testFun: func(n int) bool { + return n%2 == 0 + }, + expected: 1, + }, + { + description: "empty slice", + S: make([]int, 0), + testFun: func(n int) bool { + return n%2 == 0 + }, + expected: 0, + }, + { + description: "nil slice", + S: nil, + testFun: func(n int) bool { + return n%2 == 0 + }, + expected: 0, + }, + } + + for _, tc := range cases { + tc := tc + + t.Run(tc.description, func(t *testing.T) { + t.Parallel() + + if got, want := len(Reject(tc.S, tc.testFun)), tc.expected; !reflect.DeepEqual(got, want) { + t.Errorf("expected %v to be %v", got, want) + } + }) + } +} + +func TestSliceConcat(t *testing.T) { + t.Parallel() + + cases := []struct { + description string + S1 []int + S2 []int + expected int + }{ + { + description: "interger slice rejects even numbers", + S1: []int{0, 1, 2}, + S2: []int{3, 4}, + expected: 5, + }, + { + description: "empty slice", + S1: nil, + S2: make([]int, 0), + expected: 0, + }, + } + + for _, tc := range cases { + tc := tc + + t.Run(tc.description, func(t *testing.T) { + t.Parallel() + + if got, want := len(Concat(tc.S1, tc.S2)), tc.expected; !reflect.DeepEqual(got, want) { + t.Errorf("expected %v to be %v", got, want) + } + }) + } +} From 156edd257095234104b3d2562d639b08800ec8b8 Mon Sep 17 00:00:00 2001 From: Zhenhua Li Date: Fri, 15 Mar 2024 11:17:24 -0700 Subject: [PATCH 3/3] Change sensitive_props as resource method --- mmv1/api/resource.rb | 6 +++++- mmv1/templates/terraform/resource.html.markdown.erb | 5 ++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/mmv1/api/resource.rb b/mmv1/api/resource.rb index beed4a1f3dca..a3036a3c6d79 100644 --- a/mmv1/api/resource.rb +++ b/mmv1/api/resource.rb @@ -420,6 +420,10 @@ def root_properties end end + def sensitive_props + all_nested_properties(root_properties).select(&:sensitive) + end + # Return the product-level async object, or the resource-specific one # if one exists. def async @@ -766,4 +770,4 @@ def validate_identity end end end -end \ No newline at end of file +end diff --git a/mmv1/templates/terraform/resource.html.markdown.erb b/mmv1/templates/terraform/resource.html.markdown.erb index bc03202abe3d..f411914debeb 100644 --- a/mmv1/templates/terraform/resource.html.markdown.erb +++ b/mmv1/templates/terraform/resource.html.markdown.erb @@ -40,7 +40,6 @@ tf_subcategory = (object.__product.display_name) terraform_name = object.legacy_name || "google_#{tf_product}_#{object.name.underscore}" properties = object.all_user_properties - sensitive_props = object.all_nested_properties(object.root_properties).select(&:sensitive) # In order of preference, use TF override, # general defined timeouts, or default Timeouts timeouts = object.timeouts @@ -87,9 +86,9 @@ To get more information about <%= object.name -%>, see: ~> **Note:** <%= object.docs.note -%> <%- end -%> -<%- if !sensitive_props.empty? -%> +<%- if !object.sensitive_props.empty? -%> <%- - sense_props = sensitive_props.map! {|prop| "`"+prop.lineage+"`"}.join(', ') + sense_props = object.sensitive_props.map! {|prop| "`"+prop.lineage+"`"}.join(', ') -%> ~> **Warning:** All arguments including the following potentially sensitive