From 9082ced720eab8ea66ae3e955990c45c5166f293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=20Krivokapi=C4=87?= Date: Fri, 11 Nov 2022 13:48:41 +0100 Subject: [PATCH] Rewrite collections package as generic functions (#79) This change also bumps the Go version to 1.18. --- .circleci/config.yml | 2 +- collections/lists.go | 22 ++-- collections/lists_test.go | 147 ++++++++++++++++++---- collections/maps.go | 31 ++--- collections/maps_test.go | 252 +++++++++++++++++++++++--------------- go.mod | 25 ++-- go.sum | 39 +++--- 7 files changed, 338 insertions(+), 180 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 39ff125..5a41d60 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,6 @@ defaults: &defaults docker: - - image: 087285199408.dkr.ecr.us-east-1.amazonaws.com/circle-ci-test-image-base:go1.17-tf1.2-tg37.4-pck1.8-ci50.1 + - image: 087285199408.dkr.ecr.us-east-1.amazonaws.com/circle-ci-test-image-base:go1.18-tf1.3-tg39.1-pck1.8-ci50.7 environment: GO111MODULE: auto version: 2.1 diff --git a/collections/lists.go b/collections/lists.go index 8de2c6c..d50d6a1 100644 --- a/collections/lists.go +++ b/collections/lists.go @@ -1,7 +1,7 @@ package collections -// Return true if the given list contains the given element -func ListContainsElement(list []string, element string) bool { +// ListContainsElement returns true if the given list contains the given element +func ListContainsElement[S ~[]E, E comparable](list S, element any) bool { for _, item := range list { if item == element { return true @@ -11,9 +11,9 @@ func ListContainsElement(list []string, element string) bool { return false } -// Return a copy of the given list with all instances of the given element removed -func RemoveElementFromList(list []string, element string) []string { - out := []string{} +// RemoveElementFromList returns a copy of the given list with all instances of the given element removed +func RemoveElementFromList[S ~[]E, E comparable](list S, element any) S { + out := S{} for _, item := range list { if item != element { out = append(out, item) @@ -23,15 +23,15 @@ func RemoveElementFromList(list []string, element string) []string { } // MakeCopyOfList will return a new list that is a copy of the given list. -func MakeCopyOfList(list []string) []string { - copyOfList := make([]string, len(list)) +func MakeCopyOfList[S ~[]E, E comparable](list S) S { + copyOfList := make(S, len(list)) copy(copyOfList, list) return copyOfList } -// BatchListIntoGroupsOf will group the provided string slice into groups of size n, with the last of being truncated to -// the remaining count of strings. Returns nil if n is <= 0 -func BatchListIntoGroupsOf(slice []string, batchSize int) [][]string { +// BatchListIntoGroupsOf will group the provided slice into groups of size n, with the last of being truncated to +// the remaining count of elements. Returns nil if n is <= 0 +func BatchListIntoGroupsOf[S ~[]E, E comparable](slice S, batchSize int) []S { if batchSize <= 0 { return nil } @@ -39,7 +39,7 @@ func BatchListIntoGroupsOf(slice []string, batchSize int) [][]string { // Taken from SliceTricks: https://github.com/golang/go/wiki/SliceTricks#batching-with-minimal-allocation // Intuition: We repeatedly slice off batchSize elements from slice and append it to the output, until there // is not enough. - output := [][]string{} + output := []S{} for batchSize < len(slice) { slice, output = slice[batchSize:], append(output, slice[0:batchSize:batchSize]) } diff --git a/collections/lists_test.go b/collections/lists_test.go index 57c2325..a7efc45 100644 --- a/collections/lists_test.go +++ b/collections/lists_test.go @@ -2,20 +2,25 @@ package collections import ( "fmt" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) -func TestMakeCopyOfListMakesACopy(t *testing.T) { - original := []string{"foo", "bar", "baz"} - copyOfList := MakeCopyOfList(original) - assert.Equal(t, original, copyOfList) +func TestMakeCopyOfList(t *testing.T) { + originalStr := []string{"foo", "bar", "baz"} + copyOfListStr := MakeCopyOfList(originalStr) + assert.Equal(t, originalStr, copyOfListStr) + + originalInt := []int{1, 2, 3} + copyOfListInt := MakeCopyOfList(originalInt) + assert.Equal(t, originalInt, copyOfListInt) } func TestListContainsElement(t *testing.T) { t.Parallel() - testCases := []struct { + testCasesStr := []struct { list []string element string expected bool @@ -28,7 +33,25 @@ func TestListContainsElement(t *testing.T) { {[]string{"bar", "foo", "baz"}, "", false}, } - for _, testCase := range testCases { + for _, testCase := range testCasesStr { + actual := ListContainsElement(testCase.list, testCase.element) + assert.Equal(t, testCase.expected, actual, "For list %v and element %s", testCase.list, testCase.element) + } + + testCasesInt := []struct { + list []int + element int + expected bool + }{ + {[]int{}, 0, false}, + {[]int{}, 1, false}, + {[]int{1}, 1, true}, + {[]int{1, 2, 3}, 1, true}, + {[]int{1, 2, 3}, 4, false}, + {[]int{1, 2, 3}, 0, false}, + } + + for _, testCase := range testCasesInt { actual := ListContainsElement(testCase.list, testCase.element) assert.Equal(t, testCase.expected, actual, "For list %v and element %s", testCase.list, testCase.element) } @@ -37,7 +60,7 @@ func TestListContainsElement(t *testing.T) { func TestRemoveElementFromList(t *testing.T) { t.Parallel() - testCases := []struct { + testCasesStr := []struct { list []string element string expected []string @@ -51,7 +74,28 @@ func TestRemoveElementFromList(t *testing.T) { {[]string{"bar", "foo", "baz"}, "", []string{"bar", "foo", "baz"}}, } - for _, testCase := range testCases { + for _, testCase := range testCasesStr { + actual := RemoveElementFromList(testCase.list, testCase.element) + assert.Equal(t, testCase.expected, actual, "For list %v and element %s", testCase.list, testCase.element) + } + + type customInt int + + testCasesCustomInt := []struct { + list []customInt + element customInt + expected []customInt + }{ + {[]customInt{}, 0, []customInt{}}, + {[]customInt{}, 1, []customInt{}}, + {[]customInt{1}, 1, []customInt{}}, + {[]customInt{1}, 2, []customInt{1}}, + {[]customInt{1, 2, 3}, 1, []customInt{2, 3}}, + {[]customInt{1, 2, 3}, 4, []customInt{1, 2, 3}}, + {[]customInt{1, 2, 3}, 0, []customInt{1, 2, 3}}, + } + + for _, testCase := range testCasesCustomInt { actual := RemoveElementFromList(testCase.list, testCase.element) assert.Equal(t, testCase.expected, actual, "For list %v and element %s", testCase.list, testCase.element) } @@ -60,7 +104,7 @@ func TestRemoveElementFromList(t *testing.T) { func TestBatchListIntoGroupsOf(t *testing.T) { t.Parallel() - testCases := []struct { + testCasesStr := []struct { stringList []string n int result [][]string @@ -69,33 +113,26 @@ func TestBatchListIntoGroupsOf(t *testing.T) { []string{"macaroni", "gentoo", "magellanic", "adelie", "little", "king", "emperor"}, 2, [][]string{ - []string{"macaroni", "gentoo"}, - []string{"magellanic", "adelie"}, - []string{"little", "king"}, - []string{"emperor"}, + {"macaroni", "gentoo"}, + {"magellanic", "adelie"}, + {"little", "king"}, + {"emperor"}, }, }, { []string{"macaroni", "gentoo", "magellanic", "adelie", "king", "emperor"}, 2, [][]string{ - []string{"macaroni", "gentoo"}, - []string{"magellanic", "adelie"}, - []string{"king", "emperor"}, - }, - }, - { - []string{"macaroni", "gentoo", "magellanic"}, - 5, - [][]string{ - []string{"macaroni", "gentoo", "magellanic"}, + {"macaroni", "gentoo"}, + {"magellanic", "adelie"}, + {"king", "emperor"}, }, }, { []string{"macaroni", "gentoo", "magellanic"}, 5, [][]string{ - []string{"macaroni", "gentoo", "magellanic"}, + {"macaroni", "gentoo", "magellanic"}, }, }, { @@ -115,7 +152,7 @@ func TestBatchListIntoGroupsOf(t *testing.T) { }, } - for idx, testCase := range testCases { + for idx, testCase := range testCasesStr { t.Run(fmt.Sprintf("%s_%d", t.Name(), idx), func(t *testing.T) { t.Parallel() original := MakeCopyOfList(testCase.stringList) @@ -124,4 +161,62 @@ func TestBatchListIntoGroupsOf(t *testing.T) { assert.Equal(t, testCase.stringList, original) }) } + + testCasesInt := []struct { + intList []int + n int + result [][]int + }{ + { + []int{1, 2, 3, 4, 5, 6, 7}, + 2, + [][]int{ + {1, 2}, + {3, 4}, + {5, 6}, + {7}, + }, + }, + { + []int{1, 2, 3, 4, 5, 6}, + 2, + [][]int{ + {1, 2}, + {3, 4}, + {5, 6}, + }, + }, + { + []int{1, 2, 3}, + 5, + [][]int{ + {1, 2, 3}, + }, + }, + { + []int{1, 2, 3}, + -1, + nil, + }, + { + []int{1, 2, 3}, + 0, + nil, + }, + { + []int{}, + 7, + [][]int{}, + }, + } + + for idx, testCase := range testCasesInt { + t.Run(fmt.Sprintf("%s_%d", t.Name(), idx), func(t *testing.T) { + t.Parallel() + original := MakeCopyOfList(testCase.intList) + assert.Equal(t, BatchListIntoGroupsOf(testCase.intList, testCase.n), testCase.result) + // Make sure the function doesn't modify the original list + assert.Equal(t, testCase.intList, original) + }) + } } diff --git a/collections/maps.go b/collections/maps.go index 8238f19..6c81967 100644 --- a/collections/maps.go +++ b/collections/maps.go @@ -4,34 +4,37 @@ import ( "fmt" "sort" "strings" + + "golang.org/x/exp/constraints" + "golang.org/x/exp/maps" ) const ( DefaultKeyValueStringSliceFormat = "%s=%s" ) -// Merge all the maps into one. Sadly, Go has no generics, so this is only defined for string to interface maps. -func MergeMaps(maps ...map[string]interface{}) map[string]interface{} { - out := map[string]interface{}{} +// MergeMaps merges all the maps into one +func MergeMaps[K comparable, V any](mapsToMerge ...map[K]V) map[K]V { + out := map[K]V{} - for _, currMap := range maps { - for key, value := range currMap { - out[key] = value - } + for _, currMap := range mapsToMerge { + maps.Copy(out, currMap) } return out } -// Return the keys for the given map, sorted alphabetically -func Keys(m map[string]string) []string { - out := []string{} +// Keys returns the keys for the given map, sorted +func Keys[K constraints.Ordered, V any](m map[K]V) []K { + out := []K{} - for key, _ := range m { + for key := range m { out = append(out, key) } - sort.Strings(out) + sort.Slice(out, func(i, j int) bool { + return out[i] < out[j] + }) return out } @@ -42,8 +45,8 @@ func KeyValueStringSlice(m map[string]string) []string { } // KeyValueStringSliceWithFormat returns a string slice using the specified format, sorted alphabetically. -// The format should consist of at least two '%s' string verbs. -func KeyValueStringSliceWithFormat(m map[string]string, format string) []string { +// The format should consist of at least two format specifiers. +func KeyValueStringSliceWithFormat[K comparable, V any](m map[K]V, format string) []string { out := []string{} for key, value := range m { diff --git a/collections/maps_test.go b/collections/maps_test.go index 5cb5cb3..3b147e1 100644 --- a/collections/maps_test.go +++ b/collections/maps_test.go @@ -7,123 +7,138 @@ import ( "github.com/stretchr/testify/assert" ) -func TestMergeMapsNoMaps(t *testing.T) { +func TestMergeMaps(t *testing.T) { t.Parallel() - expected := map[string]interface{}{} - assert.Equal(t, expected, MergeMaps()) -} - -func TestMergeMapsOneEmptyMap(t *testing.T) { - t.Parallel() - - map1 := map[string]interface{}{} - - expected := map[string]interface{}{} - - assert.Equal(t, expected, MergeMaps(map1)) -} - -func TestMergeMapsMultipleEmptyMaps(t *testing.T) { - t.Parallel() - - map1 := map[string]interface{}{} - map2 := map[string]interface{}{} - map3 := map[string]interface{}{} - - expected := map[string]interface{}{} - - assert.Equal(t, expected, MergeMaps(map1, map2, map3)) -} - -func TestMergeMapsOneNonEmptyMap(t *testing.T) { - t.Parallel() - - map1 := map[string]interface{}{ - "key1": "value1", - } - - expected := map[string]interface{}{ - "key1": "value1", - } - - assert.Equal(t, expected, MergeMaps(map1)) -} - -func TestMergeMapsTwoNonEmptyMaps(t *testing.T) { - t.Parallel() - - map1 := map[string]interface{}{ - "key1": "value1", - } - - map2 := map[string]interface{}{ - "key2": "value2", - } - - expected := map[string]interface{}{ - "key1": "value1", - "key2": "value2", + testCasesStr := []struct { + name string + mapsToMerge []map[string]interface{} + expected map[string]interface{} + }{ + { + "No maps", + nil, + map[string]interface{}{}, + }, + { + "One empty map", + []map[string]interface{}{{}}, + map[string]interface{}{}, + }, + { + "Multiple empty maps", + []map[string]interface{}{{}, {}, {}}, + map[string]interface{}{}, + }, + { + "One non-empty map", + []map[string]interface{}{{"key1": "value1"}}, + map[string]interface{}{"key1": "value1"}, + }, + { + "Two non-empty maps", + []map[string]interface{}{{"key1": "value1"}, {"key2": "value2"}}, + map[string]interface{}{"key1": "value1", "key2": "value2"}, + }, + { + "Two non-empty maps, overlapping keys", + []map[string]interface{}{ + {"key1": "value1", "key3": "value3"}, + {"key1": "replacement", "key2": "value2"}, + }, + map[string]interface{}{"key1": "replacement", "key2": "value2", "key3": "value3"}, + }, + { + "Multiple non-empty maps, overlapping keys", + []map[string]interface{}{ + {"key1": "value1", "key3": "value3"}, + {"key1": "replacement", "key2": "value2"}, + {"key1": "replacement-two", "key3": "replacement-two", "key4": "value4"}, + }, + map[string]interface{}{"key1": "replacement-two", "key2": "value2", "key3": "replacement-two", "key4": "value4"}, + }, } - assert.Equal(t, expected, MergeMaps(map1, map2)) -} + for _, testCase := range testCasesStr { + // The following is necessary to make sure testCase's values don't + // get updated due to concurrency within the scope of t.Run(..) below + testCase := testCase -func TestMergeMapsTwoNonEmptyMapsOverlappingKeys(t *testing.T) { - t.Parallel() - - map1 := map[string]interface{}{ - "key1": "value1", - "key3": "value3", - } - - map2 := map[string]interface{}{ - "key1": "replacement", - "key2": "value2", - } + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() - expected := map[string]interface{}{ - "key1": "replacement", - "key2": "value2", - "key3": "value3", + actual := MergeMaps(testCase.mapsToMerge...) + assert.Equal(t, testCase.expected, actual) + }) } - assert.Equal(t, expected, MergeMaps(map1, map2)) -} - -func TestMergeMapsMultipleNonEmptyMapsOverlappingKeys(t *testing.T) { - t.Parallel() - - map1 := map[string]interface{}{ - "key1": "value1", - "key3": "value3", + testCasesInt := []struct { + name string + mapsToMerge []map[int]int + expected map[int]int + }{ + { + "No maps", + nil, + map[int]int{}, + }, + { + "One empty map", + []map[int]int{{}}, + map[int]int{}, + }, + { + "Multiple empty maps", + []map[int]int{{}, {}, {}}, + map[int]int{}, + }, + { + "One non-empty map", + []map[int]int{{1: 1}}, + map[int]int{1: 1}, + }, + { + "Two non-empty maps", + []map[int]int{{1: 1}, {2: 2}}, + map[int]int{1: 1, 2: 2}, + }, + { + "Two non-empty maps, overlapping keys", + []map[int]int{ + {1: 1, 3: 3}, + {1: 1000, 2: 2}, + }, + map[int]int{1: 1000, 2: 2, 3: 3}, + }, + { + "Multiple non-empty maps, overlapping keys", + []map[int]int{ + {1: 1, 3: 3}, + {1: 1000, 2: 2}, + {1: 1000000, 3: 3000, 4: 4}, + }, + map[int]int{1: 1000000, 2: 2, 3: 3000, 4: 4}, + }, } - map2 := map[string]interface{}{ - "key1": "replacement", - "key2": "value2", - } + for _, testCase := range testCasesInt { + // The following is necessary to make sure testCase's values don't + // get updated due to concurrency within the scope of t.Run(..) below + testCase := testCase - map3 := map[string]interface{}{ - "key1": "replacement-two", - "key3": "replacement-two", - "key4": "value4", - } + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() - expected := map[string]interface{}{ - "key1": "replacement-two", - "key2": "value2", - "key3": "replacement-two", - "key4": "value4", + actual := MergeMaps(testCase.mapsToMerge...) + assert.Equal(t, testCase.expected, actual) + }) } - - assert.Equal(t, expected, MergeMaps(map1, map2, map3)) } func TestKeys(t *testing.T) { t.Parallel() - testCases := []struct { + testCasesStr := []struct { input map[string]string expected []string }{ @@ -132,7 +147,23 @@ func TestKeys(t *testing.T) { {map[string]string{"a": "foo", "b": "bar", "c": "baz"}, []string{"a", "b", "c"}}, } - for _, testCase := range testCases { + for _, testCase := range testCasesStr { + t.Run(fmt.Sprintf("%v", testCase.input), func(t *testing.T) { + actual := Keys(testCase.input) + assert.Equal(t, testCase.expected, actual) + }) + } + + testCasesInt := []struct { + input map[int]int + expected []int + }{ + {map[int]int{}, []int{}}, + {map[int]int{1: 1}, []int{1}}, + {map[int]int{1: 1, 2: 2, 3: 3}, []int{1, 2, 3}}, + } + + for _, testCase := range testCasesInt { t.Run(fmt.Sprintf("%v", testCase.input), func(t *testing.T) { actual := Keys(testCase.input) assert.Equal(t, testCase.expected, actual) @@ -162,7 +193,7 @@ func TestKeyValueStringSlice(t *testing.T) { func TestKeyValueStringSliceWithFormat(t *testing.T) { t.Parallel() - testCases := []struct { + testCasesStr := []struct { input map[string]string format string expected []string @@ -172,7 +203,24 @@ func TestKeyValueStringSliceWithFormat(t *testing.T) { {map[string]string{"a": "foo", "b": "bar", "c": "baz"}, "%s=%s", []string{"a=foo", "b=bar", "c=baz"}}, } - for _, testCase := range testCases { + for _, testCase := range testCasesStr { + t.Run(fmt.Sprintf("%v", testCase.input), func(t *testing.T) { + actual := KeyValueStringSliceWithFormat(testCase.input, testCase.format) + assert.Equal(t, testCase.expected, actual) + }) + } + + testCasesInt := []struct { + input map[int]int + format string + expected []string + }{ + {map[int]int{1: 11}, "%d='%d'", []string{"1='11'"}}, + {map[int]int{1: 11}, "%d%d", []string{"111"}}, + {map[int]int{1: 11, 2: 22, 3: 33}, "%d=%d", []string{"1=11", "2=22", "3=33"}}, + } + + for _, testCase := range testCasesInt { t.Run(fmt.Sprintf("%v", testCase.input), func(t *testing.T) { actual := KeyValueStringSliceWithFormat(testCase.input, testCase.format) assert.Equal(t, testCase.expected, actual) diff --git a/go.mod b/go.mod index d10a2a1..af082d2 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,12 @@ module github.com/gruntwork-io/go-commons -go 1.17 +go 1.18 require ( github.com/aws/aws-sdk-go v1.44.48 github.com/aws/aws-sdk-go-v2 v1.16.16 github.com/aws/aws-sdk-go-v2/config v1.15.13 + github.com/aws/aws-sdk-go-v2/service/autoscaling v1.23.16 github.com/aws/aws-sdk-go-v2/service/ec2 v1.47.2 github.com/aws/aws-sdk-go-v2/service/s3 v1.27.1 github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.13 @@ -14,13 +15,14 @@ require ( github.com/fatih/color v1.13.0 github.com/go-errors/errors v1.4.2 github.com/google/go-github/v44 v44.1.0 - github.com/gruntwork-io/terratest v0.40.17 + github.com/gruntwork-io/terratest v0.41.0 github.com/hashicorp/go-multierror v1.1.1 github.com/mattn/go-zglob v0.0.3 github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.8.0 github.com/urfave/cli/v2 v2.10.3 - golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d + golang.org/x/crypto v0.1.0 + golang.org/x/exp v0.0.0-20221106115401-f9659909a136 golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c ) @@ -36,7 +38,6 @@ require ( github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5 // indirect - github.com/aws/aws-sdk-go-v2/service/autoscaling v1.23.16 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.9 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8 // indirect @@ -56,6 +57,7 @@ require ( github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.3 // indirect + github.com/google/go-cmp v0.5.8 // indirect github.com/google/go-github/v29 v29.0.2 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.1.0 // indirect @@ -82,6 +84,7 @@ require ( github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pquerna/otp v1.2.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect @@ -92,14 +95,13 @@ require ( github.com/zclconf/go-cty v1.9.1 // indirect go.opencensus.io v0.23.0 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect - golang.org/x/mod v0.4.2 // indirect - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect - golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/mod v0.6.0 // indirect + golang.org/x/net v0.1.0 // indirect + golang.org/x/sys v0.1.0 // indirect + golang.org/x/term v0.1.0 // indirect + golang.org/x/text v0.4.0 // indirect golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect - golang.org/x/tools v0.1.2 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/tools v0.2.0 // indirect google.golang.org/api v0.47.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect @@ -108,6 +110,7 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gotest.tools/v3 v3.0.3 // indirect k8s.io/api v0.20.6 // indirect k8s.io/apimachinery v0.20.6 // indirect k8s.io/client-go v0.20.6 // indirect diff --git a/go.sum b/go.sum index 62b6078..f89adef 100644 --- a/go.sum +++ b/go.sum @@ -64,7 +64,6 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go v1.44.48 h1:jLDC9RsNoYMLFlKpB8LdqUnoDdC2yvkS4QbuyPQJ8+M= github.com/aws/aws-sdk-go v1.44.48/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go-v2 v1.16.7 h1:zfBwXus3u14OszRxGcqCDS4MfMCv10e8SMJ2r8Xm0Ns= github.com/aws/aws-sdk-go-v2 v1.16.7/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw= github.com/aws/aws-sdk-go-v2 v1.16.16 h1:M1fj4FE2lB4NzRb9Y0xdWsn2P0+2UHVxwKyOa4YJNjk= github.com/aws/aws-sdk-go-v2 v1.16.16/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k= @@ -76,11 +75,9 @@ github.com/aws/aws-sdk-go-v2/credentials v1.12.8 h1:niTa7zc7uyOP2ufri0jPESBt1h9y github.com/aws/aws-sdk-go-v2/credentials v1.12.8/go.mod h1:P2Hd4Sy7mXRxPNcQMPBmqszSJoDXexX8XEDaT6lucO0= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8 h1:VfBdn2AxwMbFyJN/lF/xuT3SakomJ86PZu3rCxb5K0s= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8/go.mod h1:oL1Q3KuCq1D4NykQnIvtRiBGLUXhcpY5pl6QZB2XEPU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14 h1:2C0pYHcUBmdzPj+EKNC4qj97oK6yjrUhc1KoSodglvk= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14/go.mod h1:kdjrMwHwrC3+FsKhNcCMJ7tUVj/8uSD5CZXeQ4wV6fM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23 h1:s4g/wnzMf+qepSNgTvaQQHNxyMLKSawNhKCPNy++2xY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23/go.mod h1:2DFxAQ9pfIRy0imBCJv+vZ2X6RKxves6fbnEuSry6b4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8 h1:2J+jdlBJWEmTyAwC82Ym68xCykIvnSnIN18b8xHGlcc= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8/go.mod h1:ZIV8GYoC6WLBW5KGs+o4rsc65/ozd+eQ0L31XF5VDwk= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17 h1:/K482T5A3623WJgWT8w1yRAFK4RzGzEl7y39yhtn9eA= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17/go.mod h1:pRwaTYCJemADaqCbUAxltMoHKata7hmB5PjEXeu0kfg= @@ -108,7 +105,6 @@ github.com/aws/aws-sdk-go-v2/service/sso v1.11.11 h1:XOJWXNFXJyapJqQuCIPfftsOf0X github.com/aws/aws-sdk-go-v2/service/sso v1.11.11/go.mod h1:MO4qguFjs3wPGcCSpQ7kOFTwRvb+eu+fn+1vKleGHUk= github.com/aws/aws-sdk-go-v2/service/sts v1.16.9 h1:yOfILxyjmtr2ubRkRJldlHDFBhf5vw4CzhbwWIBmimQ= github.com/aws/aws-sdk-go-v2/service/sts v1.16.9/go.mod h1:O1IvkYxr+39hRf960Us6j0x1P8pDqhTX+oXM5kQNl/Y= -github.com/aws/smithy-go v1.12.0 h1:gXpeZel/jPoWQ7OEmLIgCUnhkFftqNfwWUwAHSlp1v0= github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aws/smithy-go v1.13.3 h1:l7LYxGuzK6/K+NzJ2mC+VvLUbae0sL3bXU//04MkmnA= github.com/aws/smithy-go v1.13.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= @@ -270,8 +266,8 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/gruntwork-io/terratest v0.40.17 h1:veSr7MUtk5GRDg5/pZ9qLUvrylr7yuRw0fY9UaSHbuI= -github.com/gruntwork-io/terratest v0.40.17/go.mod h1:enUpxNMsQfiJTTJMGqiznxohqJ4cYPU+nzI3bQNw1WM= +github.com/gruntwork-io/terratest v0.41.0 h1:QKFK6m0EMVnrV7lw2L06TlG+Ha3t0CcOXuBVywpeNRU= +github.com/gruntwork-io/terratest v0.41.0/go.mod h1:qH1xkPTTGx30XkMHw8jAVIbzqheSjIa5IyiTwSV2vKI= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= @@ -365,6 +361,8 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -381,6 +379,7 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -432,8 +431,8 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -444,6 +443,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20221106115401-f9659909a136 h1:Fq7F/w7MAa1KJ5bt2aJ62ihqp9HDcRuyILskkpIAurw= +golang.org/x/exp v0.0.0-20221106115401-f9659909a136/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -469,8 +470,9 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -510,8 +512,9 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -585,11 +588,13 @@ golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e h1:w36l2Uw3dRan1K3TyXriXvY+6T56GNmlKGcqiQUJDfM= golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -598,8 +603,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -617,6 +623,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -655,12 +662,12 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -790,6 +797,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=