diff --git a/tools/data-api-differ/internal/changes/common_types_api_version_added.go b/tools/data-api-differ/internal/changes/common_types_api_version_added.go new file mode 100644 index 00000000000..48bd012c9bf --- /dev/null +++ b/tools/data-api-differ/internal/changes/common_types_api_version_added.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package changes + +var _ Change = CommonTypesApiVersionAdded{} + +// CommonTypesApiVersionAdded defines information about a new API Version for CommonTypes. +type CommonTypesApiVersionAdded struct { + // ApiVersion specifies the API Version (e.g. `2023-01-01-preview`) for which CommonTypes have been added. + ApiVersion string +} + +// IsBreaking returns whether this Change is considered a Breaking Change. +func (CommonTypesApiVersionAdded) IsBreaking() bool { + return false +} diff --git a/tools/data-api-differ/internal/changes/common_types_api_version_removed.go b/tools/data-api-differ/internal/changes/common_types_api_version_removed.go new file mode 100644 index 00000000000..08c31513687 --- /dev/null +++ b/tools/data-api-differ/internal/changes/common_types_api_version_removed.go @@ -0,0 +1,17 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package changes + +var _ Change = CommonTypesApiVersionRemoved{} + +// CommonTypesApiVersionRemoved defines information about a new API Version for CommonTypes. +type CommonTypesApiVersionRemoved struct { + // ApiVersion specifies the API Version (e.g. `2023-01-01-preview`) for which CommonTypes have been removed. + ApiVersion string +} + +// IsBreaking returns whether this Change is considered a Breaking Change. +func (CommonTypesApiVersionRemoved) IsBreaking() bool { + return true +} diff --git a/tools/data-api-differ/internal/changes/common_types_constant_added.go b/tools/data-api-differ/internal/changes/common_types_constant_added.go new file mode 100644 index 00000000000..1c5d6f6c4e5 --- /dev/null +++ b/tools/data-api-differ/internal/changes/common_types_constant_added.go @@ -0,0 +1,29 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package changes + +var _ Change = CommonTypesConstantAdded{} + +// CommonTypesConstantAdded defines information about a new CommonTypes Constant. +type CommonTypesConstantAdded struct { + // ApiVersion specifies the name of the CommonTypes API Version which contains this Constant. + ApiVersion string + + // ResourceName specifies the name of the API Resource which contains this Constant. + ResourceName string + + // ConstantName specifies the name of the Constant which has been added. + ConstantName string + + // ConstantType specifies the type of Constant (e.g. Int/String) that this is. + ConstantType string + + // KeysAndValues specifies the Keys and Values for the Constant which has been added. + KeysAndValues map[string]string +} + +// IsBreaking returns whether this Change is considered a Breaking Change. +func (CommonTypesConstantAdded) IsBreaking() bool { + return false +} diff --git a/tools/data-api-differ/internal/changes/common_types_constant_key_value_added.go b/tools/data-api-differ/internal/changes/common_types_constant_key_value_added.go new file mode 100644 index 00000000000..b7b7313c9a2 --- /dev/null +++ b/tools/data-api-differ/internal/changes/common_types_constant_key_value_added.go @@ -0,0 +1,26 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package changes + +var _ Change = CommonTypesConstantKeyValueAdded{} + +// CommonTypesConstantKeyValueAdded specifies when a new Key/Value combination is added to an existing CommonTypes Constant. +type CommonTypesConstantKeyValueAdded struct { + // ApiVersion specifies the name of the API Version which contains this CommonTypes Constant. + ApiVersion string + + // ConstantName specifies the name of the Constant which has been updated. + ConstantName string + + // ConstantKey specifies the key for this new Constant Key/Value. + ConstantKey string + + // ConstantValue specifies the value for this new Constant Key/Value. + ConstantValue string +} + +// IsBreaking returns whether this Change is considered a Breaking Change. +func (CommonTypesConstantKeyValueAdded) IsBreaking() bool { + return false +} diff --git a/tools/data-api-differ/internal/changes/common_types_constant_key_value_changed.go b/tools/data-api-differ/internal/changes/common_types_constant_key_value_changed.go new file mode 100644 index 00000000000..6c1dc6dc656 --- /dev/null +++ b/tools/data-api-differ/internal/changes/common_types_constant_key_value_changed.go @@ -0,0 +1,29 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package changes + +var _ Change = CommonTypesConstantKeyValueChanged{} + +// CommonTypesConstantKeyValueChanged specifies when Constant Key has a new Value +type CommonTypesConstantKeyValueChanged struct { + // ApiVersion specifies the name of the API Version which contains this CommonTypes Constant. + ApiVersion string + + // ConstantName specifies the name of the Constant which has an updated value. + ConstantName string + + // ConstantKey specifies the key within the Constant which has changed. + ConstantKey string + + // OldConstantValue specifies the old Value for this Constant Key. + OldConstantValue string + + // NewConstantValue specifies the new/updated Value for this Constant Key. + NewConstantValue string +} + +// IsBreaking returns whether this Change is considered a Breaking Change. +func (CommonTypesConstantKeyValueChanged) IsBreaking() bool { + return true +} diff --git a/tools/data-api-differ/internal/changes/common_types_constant_key_value_removed.go b/tools/data-api-differ/internal/changes/common_types_constant_key_value_removed.go new file mode 100644 index 00000000000..aec44c58503 --- /dev/null +++ b/tools/data-api-differ/internal/changes/common_types_constant_key_value_removed.go @@ -0,0 +1,26 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package changes + +var _ Change = CommonTypesConstantKeyValueRemoved{} + +// CommonTypesConstantKeyValueRemoved specifies when a Key/Value combination is removed to an existing Constant. +type CommonTypesConstantKeyValueRemoved struct { + // ApiVersion specifies the name of the API Version which contains this CommonTypes Constant. + ApiVersion string + + // ConstantName specifies the name of the Constant which has been updated. + ConstantName string + + // ConstantKey specifies the key for the Constant Key/Value which has been removed. + ConstantKey string + + // ConstantValue specifies the value for the Constant Key/Value which has been removed + ConstantValue string +} + +// IsBreaking returns whether this Change is considered a Breaking Change. +func (CommonTypesConstantKeyValueRemoved) IsBreaking() bool { + return true +} diff --git a/tools/data-api-differ/internal/changes/common_types_constant_removed.go b/tools/data-api-differ/internal/changes/common_types_constant_removed.go new file mode 100644 index 00000000000..3b9d7f5f0f1 --- /dev/null +++ b/tools/data-api-differ/internal/changes/common_types_constant_removed.go @@ -0,0 +1,26 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package changes + +var _ Change = CommonTypesConstantRemoved{} + +// CommonTypesConstantRemoved defines information about a new CommonTypes Constant. +type CommonTypesConstantRemoved struct { + // ApiVersion specifies the name of the CommonTypes API Version which contains this Constant. + ApiVersion string + + // ConstantName specifies the name of the Constant which has been removed. + ConstantName string + + // ConstantType specifies the type of Constant (e.g. Int/String) that this is. + ConstantType string + + // KeysAndValues specifies the Keys and Values for the Constant which has been removed. + KeysAndValues map[string]string +} + +// IsBreaking returns whether this Change is considered a Breaking Change. +func (CommonTypesConstantRemoved) IsBreaking() bool { + return true +} diff --git a/tools/data-api-differ/internal/changes/common_types_constant_type_changed.go b/tools/data-api-differ/internal/changes/common_types_constant_type_changed.go new file mode 100644 index 00000000000..c151f4de8fd --- /dev/null +++ b/tools/data-api-differ/internal/changes/common_types_constant_type_changed.go @@ -0,0 +1,27 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package changes + +var _ Change = CommonTypesConstantTypeChanged{} + +// CommonTypesConstantTypeChanged specifies when a CommonTypes Constant has changed Type (e.g. `int` -> `string`) +type CommonTypesConstantTypeChanged struct { + // ApiVersion specifies the name of the API Version which contains this CommonTypes Constant. + ApiVersion string + + // ConstantName specifies the name of the Constant which has changed. + ConstantName string + + // OldType specifies the old type value for this Constant + OldType string + + // NewType specifies the new/updated type value for this Constant + NewType string +} + +// IsBreaking returns whether this Change is considered a Breaking Change. +func (c CommonTypesConstantTypeChanged) IsBreaking() bool { + // If a constant changes type, this is going to require code changes to account for this + return true +} diff --git a/tools/data-api-differ/internal/changes/common_types_model_added.go b/tools/data-api-differ/internal/changes/common_types_model_added.go new file mode 100644 index 00000000000..75cc0b41988 --- /dev/null +++ b/tools/data-api-differ/internal/changes/common_types_model_added.go @@ -0,0 +1,20 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package changes + +var _ Change = CommonTypesModelAdded{} + +// CommonTypesModelAdded defines information about a new CommonTypes Model. +type CommonTypesModelAdded struct { + // ApiVersion specifies the name of the CommonTypes API Version which contains this Model. + ApiVersion string + + // ModelName specifies the name of the Model which has been added. + ModelName string +} + +// IsBreaking returns whether this Change is considered a Breaking Change. +func (CommonTypesModelAdded) IsBreaking() bool { + return false +} diff --git a/tools/data-api-differ/internal/changes/common_types_model_removed.go b/tools/data-api-differ/internal/changes/common_types_model_removed.go new file mode 100644 index 00000000000..e5e44fd275c --- /dev/null +++ b/tools/data-api-differ/internal/changes/common_types_model_removed.go @@ -0,0 +1,20 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package changes + +var _ Change = CommonTypesModelRemoved{} + +// CommonTypesModelRemoved defines information about a CommonTypes Model which has been Removed. +type CommonTypesModelRemoved struct { + // ApiVersion specifies the name of the CommonTypes API Version which contained this Model. + ApiVersion string + + // ModelName specifies the name of the Model which has been removed. + ModelName string +} + +// IsBreaking returns whether this Change is considered a Breaking Change. +func (CommonTypesModelRemoved) IsBreaking() bool { + return true +} diff --git a/tools/data-api-differ/internal/changes/constant_type_changed.go b/tools/data-api-differ/internal/changes/constant_type_changed.go index 63155f1d9e4..9103d4bae79 100644 --- a/tools/data-api-differ/internal/changes/constant_type_changed.go +++ b/tools/data-api-differ/internal/changes/constant_type_changed.go @@ -27,7 +27,6 @@ type ConstantTypeChanged struct { } // IsBreaking returns whether this Change is considered a Breaking Change. - func (c ConstantTypeChanged) IsBreaking() bool { // If a constant changes type, this is going to require code changes to account for this return true diff --git a/tools/data-api-differ/internal/differ/differ.go b/tools/data-api-differ/internal/differ/differ.go index 77290138540..a611361e0c7 100644 --- a/tools/data-api-differ/internal/differ/differ.go +++ b/tools/data-api-differ/internal/differ/differ.go @@ -5,7 +5,6 @@ package differ import ( "fmt" - "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" "github.com/hashicorp/pandora/tools/data-api-differ/internal/log" v1 "github.com/hashicorp/pandora/tools/data-api-sdk/v1" @@ -18,13 +17,19 @@ func performDiff(initial, updated v1.LoadAllDataResult, includeNestedChangesWhen diff := differ{} output := make([]changes.Change, 0) - // TODO: support additional Data Sources when we're using the updated SDK - log.Logger.Trace("Detecting changes to the Resource Manager Services..") - resourceManagerChanges, err := diff.changesForServices(initial.Services, updated.Services, includeNestedChangesWhenNew) + log.Logger.Trace("Detecting changes to Common Types..") + commonTypesChanges, err := diff.changesForCommonTypes(initial.CommonTypes, updated.CommonTypes, includeNestedChangesWhenNew) + if err != nil { + return nil, fmt.Errorf("determining changes for the Common Types: %+v", err) + } + output = append(output, *commonTypesChanges...) + + log.Logger.Trace("Detecting changes to the Services..") + serviceChanges, err := diff.changesForServices(initial.Services, updated.Services, includeNestedChangesWhenNew) if err != nil { - return nil, fmt.Errorf("determining changes for the Resource Manager Services: %+v", err) + return nil, fmt.Errorf("determining changes for the Services: %+v", err) } - output = append(output, *resourceManagerChanges...) + output = append(output, *serviceChanges...) return &Result{ Changes: output, diff --git a/tools/data-api-differ/internal/differ/differ_api_resource.go b/tools/data-api-differ/internal/differ/differ_api_resource.go index a4c4317f783..e0b925dc0a8 100644 --- a/tools/data-api-differ/internal/differ/differ_api_resource.go +++ b/tools/data-api-differ/internal/differ/differ_api_resource.go @@ -5,8 +5,6 @@ package differ import ( "fmt" - "sort" - "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" "github.com/hashicorp/pandora/tools/data-api-differ/internal/log" "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" @@ -15,7 +13,7 @@ import ( // changesForApiResources determines the changes between the API Resources within the specified API Version. func (d differ) changesForApiResources(serviceName, apiVersion string, initial, updated map[string]models.APIResource, includeNestedChangesWhenNew bool) (*[]changes.Change, error) { output := make([]changes.Change, 0) - apiResources := d.uniqueApiResources(initial, updated) + apiResources := uniqueKeys(initial, updated) for _, apiResource := range apiResources { log.Logger.Trace(fmt.Sprintf("Detecting changes in API Resource %q..", apiResource)) changesForApiResource, err := d.changesForApiResource(serviceName, apiVersion, apiResource, initial, updated, includeNestedChangesWhenNew) @@ -93,21 +91,3 @@ func (d differ) changesForApiResource(serviceName, apiVersion, apiResource strin return &output, nil } - -// uniqueApiResources returns a unique, sorted list of API Resources from the keys of initial and updated. -func (d differ) uniqueApiResources(initial, updated map[string]models.APIResource) []string { - uniqueNames := make(map[string]struct{}) - for name := range initial { - uniqueNames[name] = struct{}{} - } - for name := range updated { - uniqueNames[name] = struct{}{} - } - - output := make([]string, 0) - for k := range uniqueNames { - output = append(output, k) - } - sort.Strings(output) - return output -} diff --git a/tools/data-api-differ/internal/differ/differ_api_versions.go b/tools/data-api-differ/internal/differ/differ_api_versions.go index 1c0f1a5025c..165aa48420a 100644 --- a/tools/data-api-differ/internal/differ/differ_api_versions.go +++ b/tools/data-api-differ/internal/differ/differ_api_versions.go @@ -5,8 +5,6 @@ package differ import ( "fmt" - "sort" - "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" "github.com/hashicorp/pandora/tools/data-api-differ/internal/log" "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" @@ -15,7 +13,7 @@ import ( // changesForApiVersions determines the changes between the different API versions for the provided Service. func (d differ) changesForApiVersions(serviceName string, initial, updated map[string]models.APIVersion, includeNestedChangesWhenNew bool) (*[]changes.Change, error) { output := make([]changes.Change, 0) - apiVersions := d.uniqueApiVersions(initial, updated) + apiVersions := uniqueKeys(initial, updated) for _, apiVersion := range apiVersions { log.Logger.Trace(fmt.Sprintf("Detecting changes in API Version %q..", apiVersion)) changesForApiVersion, err := d.changesForApiVersion(serviceName, apiVersion, initial, updated, includeNestedChangesWhenNew) @@ -66,21 +64,3 @@ func (d differ) changesForApiVersion(serviceName, apiVersion string, initial, up return &output, nil } - -// uniqueApiVersions returns a unique, sorted list of API Versions from the keys of initial and updated. -func (d differ) uniqueApiVersions(initial, updated map[string]models.APIVersion) []string { - uniqueNames := make(map[string]struct{}) - for name := range initial { - uniqueNames[name] = struct{}{} - } - for name := range updated { - uniqueNames[name] = struct{}{} - } - - output := make([]string, 0) - for k := range uniqueNames { - output = append(output, k) - } - sort.Strings(output) - return output -} diff --git a/tools/data-api-differ/internal/differ/differ_common_types.go b/tools/data-api-differ/internal/differ/differ_common_types.go new file mode 100644 index 00000000000..f342ddf57c1 --- /dev/null +++ b/tools/data-api-differ/internal/differ/differ_common_types.go @@ -0,0 +1,68 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package differ + +import ( + "fmt" + + "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" + "github.com/hashicorp/pandora/tools/data-api-differ/internal/log" + "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" +) + +const commonTypesServiceName = "common-types" + +// changesForCommonTypes determines the changes between the initial and updated set of Common Types. +func (d differ) changesForCommonTypes(initial, updated map[string]models.CommonTypes, includeNestedChangesWhenNew bool) (*[]changes.Change, error) { + output := make([]changes.Change, 0) + // first pull out a unique list of APIVersions for the Common Types + log.Logger.Info("Identifying a unique list of APIVersions for Common Types..") + apiVersions := uniqueKeys(initial, updated) + for _, apiVersion := range apiVersions { + log.Logger.Info(fmt.Sprintf("Detecting changes to the Common Types in API Version %q..", apiVersion)) + changesForCommonType, err := d.changesForCommonTypesInAPIVersion(apiVersion, initial, updated, includeNestedChangesWhenNew) + if err != nil { + return nil, fmt.Errorf("detecting changes to the Common Types in API Version %q: %+v", apiVersion, err) + } + output = append(output, *changesForCommonType...) + } + return &output, nil +} + +func (d differ) changesForCommonTypesInAPIVersion(apiVersion string, initial, updated map[string]models.CommonTypes, includeNestedChangesWhenNew bool) (*[]changes.Change, error) { + oldData, inOldData := initial[apiVersion] + updatedData, inUpdatedData := updated[apiVersion] + output := make([]changes.Change, 0) + if inOldData && !inUpdatedData { + log.Logger.Trace(fmt.Sprintf("Common Types no longer contains data for API Version %q", apiVersion)) + output = append(output, changes.CommonTypesApiVersionRemoved{ + ApiVersion: apiVersion, + }) + // no point continuing to diff if it's gone + return &output, nil + } + if !inOldData && inUpdatedData { + log.Logger.Trace(fmt.Sprintf("Common Types contains a new set of data for API Version %q", apiVersion)) + output = append(output, changes.CommonTypesApiVersionAdded{ + ApiVersion: apiVersion, + }) + // intentionally not returning here + } + if !includeNestedChangesWhenNew { + return &output, nil + } + + log.Logger.Debug("Determining the changes for the CommonTypes Constants..") + changesToConstants := d.changesForCommonTypesConstants(apiVersion, oldData.Constants, updatedData.Constants) + output = append(output, changesToConstants...) + + log.Logger.Debug("Determining the changes for the CommonTypes Models..") + changesToModels, err := d.changesForCommonTypesModels(apiVersion, oldData.Models, updatedData.Models) + if err != nil { + return nil, fmt.Errorf("determining the changes for the CommonTypes Models: %+v", err) + } + output = append(output, *changesToModels...) + + return &output, nil +} diff --git a/tools/data-api-differ/internal/differ/differ_common_types_constants.go b/tools/data-api-differ/internal/differ/differ_common_types_constants.go new file mode 100644 index 00000000000..69c70e9a868 --- /dev/null +++ b/tools/data-api-differ/internal/differ/differ_common_types_constants.go @@ -0,0 +1,105 @@ +package differ + +import ( + "fmt" + + "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" + "github.com/hashicorp/pandora/tools/data-api-differ/internal/log" + "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" +) + +func (d differ) changesForCommonTypesConstants(apiVersion string, initial, updated map[string]models.SDKConstant) []changes.Change { + output := make([]changes.Change, 0) + constantNames := uniqueKeys(initial, updated) + for _, constantName := range constantNames { + log.Logger.Trace(fmt.Sprintf("Detecting changes in CommonTypes Constant %q..", constantName)) + changesForConstant := d.changesForCommonTypesConstant(apiVersion, constantName, initial, updated) + output = append(output, changesForConstant...) + } + return output +} + +// changesForCommonTypesConstant determines the changes between two different versions of the same CommonTypes Constant. +func (d differ) changesForCommonTypesConstant(apiVersion, constantName string, initial, updated map[string]models.SDKConstant) []changes.Change { + output := make([]changes.Change, 0) + + oldData, inOldData := initial[constantName] + updatedData, inUpdatedData := updated[constantName] + if inOldData && !inUpdatedData { + log.Logger.Trace(fmt.Sprintf("CommonTypes Constant %q not present in the updated data", constantName)) + output = append(output, changes.CommonTypesConstantRemoved{ + ApiVersion: apiVersion, + ConstantName: constantName, + ConstantType: string(oldData.Type), + KeysAndValues: oldData.Values, + }) + // no point continuing to diff if it's gone + return output + } + if !inOldData && inUpdatedData { + log.Logger.Trace(fmt.Sprintf("CommonTypes Constant %q is new", constantName)) + output = append(output, changes.CommonTypesConstantAdded{ + ApiVersion: apiVersion, + ConstantName: constantName, + ConstantType: string(updatedData.Type), + KeysAndValues: updatedData.Values, + }) + // return here since `CommonTypesConstantAdded` contains the details + return output + } + + if inOldData && inUpdatedData { + // the Type changing would be problematic - so we should surface that + if oldData.Type != updatedData.Type { + output = append(output, changes.CommonTypesConstantTypeChanged{ + ApiVersion: apiVersion, + ConstantName: constantName, + OldType: string(oldData.Type), + NewType: string(updatedData.Type), + }) + } + } + + keys := uniqueKeys(oldData.Values, updatedData.Values) + for _, key := range keys { + log.Logger.Trace(fmt.Sprintf("Detecting changes in Constant Key %q..", key)) + oldValue, oldContainsKey := oldData.Values[key] + updatedValue, updatedContainsKey := updatedData.Values[key] + + if oldContainsKey && !updatedContainsKey { + log.Logger.Trace("Key %q / Value %q has been removed", key, oldValue) + output = append(output, changes.CommonTypesConstantKeyValueRemoved{ + ApiVersion: apiVersion, + ConstantName: constantName, + ConstantKey: key, + ConstantValue: oldValue, + }) + continue + } + if !oldContainsKey && updatedContainsKey { + log.Logger.Trace("Key %q / Value %q has been added", key, updatedValue) + output = append(output, changes.CommonTypesConstantKeyValueAdded{ + ApiVersion: apiVersion, + ConstantName: constantName, + ConstantKey: key, + ConstantValue: updatedValue, + }) + continue + } + + // NOTE: if the casing of the Value changes this would be a breaking change too + if oldValue != updatedValue { + log.Logger.Trace("Key %q has changed value from %q to %q", key, oldValue, updatedValue) + output = append(output, changes.CommonTypesConstantKeyValueChanged{ + ApiVersion: apiVersion, + ConstantName: constantName, + ConstantKey: key, + OldConstantValue: oldValue, + NewConstantValue: updatedValue, + }) + continue + } + } + + return output +} diff --git a/tools/data-api-differ/internal/differ/differ_common_types_constants_test.go b/tools/data-api-differ/internal/differ/differ_common_types_constants_test.go new file mode 100644 index 00000000000..8a857578b8c --- /dev/null +++ b/tools/data-api-differ/internal/differ/differ_common_types_constants_test.go @@ -0,0 +1,258 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package differ + +import ( + "testing" + + "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" + "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" +) + +func TestDiff_CommonTypesConstantNoChanges(t *testing.T) { + initial := map[string]models.SDKConstant{ + "First": { + Type: models.IntegerSDKConstantType, + Values: map[string]string{ + "One": "1", + "Two": "2", + "Three": "3", + }, + }, + } + updated := map[string]models.SDKConstant{ + "First": { + Type: models.IntegerSDKConstantType, + Values: map[string]string{ + "One": "1", + "Two": "2", + "Three": "3", + }, + }, + } + actual := differ{}.changesForCommonTypesConstants("2020-01-01", initial, updated) + expected := make([]changes.Change, 0) + assertChanges(t, expected, actual) + assertContainsNoBreakingChanges(t, actual) +} + +func TestDiff_CommonTypesConstantAdded(t *testing.T) { + initial := map[string]models.SDKConstant{ + "First": {}, + } + updated := map[string]models.SDKConstant{ + "First": {}, + "Second": { + Type: models.IntegerSDKConstantType, + Values: map[string]string{ + "One": "1", + "Two": "2", + "Three": "3", + }, + }, + } + actual := differ{}.changesForCommonTypesConstants("2020-01-01", initial, updated) + expected := []changes.Change{ + changes.CommonTypesConstantAdded{ + ApiVersion: "2020-01-01", + ConstantName: "Second", + ConstantType: string(models.IntegerSDKConstantType), + KeysAndValues: map[string]string{ + "One": "1", + "Two": "2", + "Three": "3", + }, + }, + } + assertChanges(t, expected, actual) + assertContainsNoBreakingChanges(t, actual) +} + +func TestDiff_CommonTypesConstantRemoved(t *testing.T) { + initial := map[string]models.SDKConstant{ + "First": {}, + "Second": { + Type: models.IntegerSDKConstantType, + Values: map[string]string{ + "One": "1", + "Two": "2", + "Three": "3", + }, + }, + } + updated := map[string]models.SDKConstant{ + "First": {}, + } + actual := differ{}.changesForCommonTypesConstants("2020-01-01", initial, updated) + expected := []changes.Change{ + changes.CommonTypesConstantRemoved{ + ApiVersion: "2020-01-01", + ConstantName: "Second", + ConstantType: string(models.IntegerSDKConstantType), + KeysAndValues: map[string]string{ + "One": "1", + "Two": "2", + "Three": "3", + }, + }, + } + assertChanges(t, expected, actual) + assertContainsBreakingChanges(t, actual) +} + +func TestDiff_CommonTypesConstantKeyValueAdded(t *testing.T) { + initial := map[string]models.SDKConstant{ + "First": { + Type: models.IntegerSDKConstantType, + Values: map[string]string{ + "One": "1", + "Two": "2", + "Three": "3", + }, + }, + } + updated := map[string]models.SDKConstant{ + "First": { + Type: models.IntegerSDKConstantType, + Values: map[string]string{ + "One": "1", + "Two": "2", + "Three": "3", + "Four": "4", + }, + }, + } + actual := differ{}.changesForCommonTypesConstants("2020-01-01", initial, updated) + expected := []changes.Change{ + changes.CommonTypesConstantKeyValueAdded{ + ApiVersion: "2020-01-01", + ConstantName: "First", + ConstantKey: "Four", + ConstantValue: "4", + }, + } + assertChanges(t, expected, actual) + assertContainsNoBreakingChanges(t, actual) +} + +func TestDiff_CommonTypesConstantKeyValueChanged(t *testing.T) { + initial := map[string]models.SDKConstant{ + "SkuName": { + Type: models.StringSDKConstantType, + Values: map[string]string{ + "Basic": "basic", + "Premium": "premium", + "Standard": "standard", + }, + }, + } + updated := map[string]models.SDKConstant{ + "SkuName": { + Type: models.StringSDKConstantType, + Values: map[string]string{ + "Basic": "Basic", + "Premium": "Premium", + "Standard": "Standard", + }, + }, + } + actual := differ{}.changesForCommonTypesConstants("2020-01-01", initial, updated) + expected := []changes.Change{ + changes.CommonTypesConstantKeyValueChanged{ + ApiVersion: "2020-01-01", + ConstantName: "SkuName", + ConstantKey: "Basic", + OldConstantValue: "basic", + NewConstantValue: "Basic", + }, + changes.CommonTypesConstantKeyValueChanged{ + ApiVersion: "2020-01-01", + ConstantName: "SkuName", + ConstantKey: "Premium", + OldConstantValue: "premium", + NewConstantValue: "Premium", + }, + changes.CommonTypesConstantKeyValueChanged{ + ApiVersion: "2020-01-01", + ConstantName: "SkuName", + ConstantKey: "Standard", + OldConstantValue: "standard", + NewConstantValue: "Standard", + }, + } + assertChanges(t, expected, actual) + assertContainsBreakingChanges(t, actual) +} + +func TestDiff_CommonTypesConstantKeyValueRemoved(t *testing.T) { + initial := map[string]models.SDKConstant{ + "First": { + Type: models.IntegerSDKConstantType, + Values: map[string]string{ + "One": "1", + "Two": "2", + "Three": "3", + "Four": "4", + }, + }, + } + updated := map[string]models.SDKConstant{ + "First": { + Type: models.IntegerSDKConstantType, + Values: map[string]string{ + "One": "1", + "Two": "2", + "Three": "3", + }, + }, + } + actual := differ{}.changesForCommonTypesConstants("2020-01-01", initial, updated) + expected := []changes.Change{ + changes.CommonTypesConstantKeyValueRemoved{ + ApiVersion: "2020-01-01", + ConstantName: "First", + ConstantKey: "Four", + ConstantValue: "4", + }, + } + assertChanges(t, expected, actual) + assertContainsBreakingChanges(t, actual) +} + +func TestDiff_CommonTypesConstantTypeChanged(t *testing.T) { + initial := map[string]models.SDKConstant{ + "First": { + Type: models.IntegerSDKConstantType, + Values: map[string]string{ + "One": "1", + }, + }, + } + updated := map[string]models.SDKConstant{ + "First": { + Type: models.StringSDKConstantType, + Values: map[string]string{ + "One": "one", + }, + }, + } + actual := differ{}.changesForCommonTypesConstants("2020-01-01", initial, updated) + expected := []changes.Change{ + changes.CommonTypesConstantTypeChanged{ + ApiVersion: "2020-01-01", + ConstantName: "First", + OldType: string(models.IntegerSDKConstantType), + NewType: string(models.StringSDKConstantType), + }, + changes.CommonTypesConstantKeyValueChanged{ + ApiVersion: "2020-01-01", + ConstantName: "First", + ConstantKey: "One", + OldConstantValue: "1", + NewConstantValue: "one", + }, + } + assertChanges(t, expected, actual) + assertContainsBreakingChanges(t, actual) +} diff --git a/tools/data-api-differ/internal/differ/differ_common_types_models.go b/tools/data-api-differ/internal/differ/differ_common_types_models.go new file mode 100644 index 00000000000..0e328d91aa7 --- /dev/null +++ b/tools/data-api-differ/internal/differ/differ_common_types_models.go @@ -0,0 +1,67 @@ +package differ + +import ( + "fmt" + + "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" + "github.com/hashicorp/pandora/tools/data-api-differ/internal/log" + "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" +) + +func (d differ) changesForCommonTypesModels(apiVersion string, initial, updated map[string]models.SDKModel) (*[]changes.Change, error) { + output := make([]changes.Change, 0) + modelNames := uniqueKeys(initial, updated) + for _, modelName := range modelNames { + log.Logger.Trace(fmt.Sprintf("Detecting changes in CommonTypes Model %q..", modelName)) + changesForModel, err := d.changesForCommonTypesModel(apiVersion, modelName, initial, updated) + if err != nil { + return nil, fmt.Errorf("detecting changes to the CommonTypes Model %q: %+v", modelName, err) + } + output = append(output, *changesForModel...) + } + return &output, nil +} + +// changesForCommonTypesModel determines the changes between the initial and updated CommonTypes Model. +func (d differ) changesForCommonTypesModel(apiVersion, modelName string, initial, updated map[string]models.SDKModel) (*[]changes.Change, error) { + output := make([]changes.Change, 0) + + oldData, isInOld := initial[modelName] + updatedData, isInUpdated := updated[modelName] + if isInOld && !isInUpdated { + log.Logger.Trace(fmt.Sprintf("CommonTypes Model %q has been removed", modelName)) + output = append(output, changes.CommonTypesModelRemoved{ + ApiVersion: apiVersion, + ModelName: modelName, + }) + return &output, nil + } + if !isInOld && isInUpdated { + log.Logger.Trace(fmt.Sprintf("CommonTypes Model %q is new", modelName)) + output = append(output, changes.CommonTypesModelAdded{ + ApiVersion: apiVersion, + ModelName: modelName, + }) + // in the event of a new model, we can skip the other details + return &output, nil + } + + // @tombuildsstuff: I've opted to reuse the existing diffing logic, since these are the same models + // and I don't think it's worth having a new type specifically for each change for CommonModels until + // that changes - so this is fine for now. + + // check for any changes to the discriminated information + log.Logger.Trace("Checking for changes to the Discriminated Type Information..") + discriminatorChangesForModel := d.discriminatorChangesForModel(commonTypesServiceName, apiVersion, commonTypesServiceName, modelName, oldData, updatedData) + output = append(output, discriminatorChangesForModel...) + + // then detect any changes to the fields + log.Logger.Trace("Checking for changes to the Fields..") + changesToFields, err := d.changesForFields(commonTypesServiceName, apiVersion, commonTypesServiceName, modelName, oldData.Fields, updatedData.Fields) + if err != nil { + return nil, fmt.Errorf("detecting changes to Fields: %+v", err) + } + output = append(output, *changesToFields...) + + return &output, nil +} diff --git a/tools/data-api-differ/internal/differ/differ_common_types_models_test.go b/tools/data-api-differ/internal/differ/differ_common_types_models_test.go new file mode 100644 index 00000000000..d5bce284643 --- /dev/null +++ b/tools/data-api-differ/internal/differ/differ_common_types_models_test.go @@ -0,0 +1,233 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package differ + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" + "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" +) + +func TestDiff_CommonTypesModelNoChanges(t *testing.T) { + initial := map[string]models.SDKModel{ + "First": { + Fields: map[string]models.SDKField{ + "Example": { + ObjectDefinition: models.SDKObjectDefinition{ + Type: models.StringSDKObjectDefinitionType, + }, + Required: true, + }, + }, + }, + } + updated := map[string]models.SDKModel{ + "First": { + Fields: map[string]models.SDKField{ + "Example": { + ObjectDefinition: models.SDKObjectDefinition{ + Type: models.StringSDKObjectDefinitionType, + }, + Required: true, + }, + }, + }, + } + actual, err := differ{}.changesForCommonTypesModels("2020-01-01", initial, updated) + if err != nil { + t.Fatalf(err.Error()) + } + expected := make([]changes.Change, 0) + assertChanges(t, expected, *actual) + assertContainsNoBreakingChanges(t, *actual) +} + +func TestDiff_CommonTypesModelAdded(t *testing.T) { + initial := map[string]models.SDKModel{ + "First": {}, + } + updated := map[string]models.SDKModel{ + "First": {}, + "Second": {}, + } + actual, err := differ{}.changesForCommonTypesModels("2020-01-01", initial, updated) + if err != nil { + t.Fatalf(err.Error()) + } + expected := []changes.Change{ + changes.CommonTypesModelAdded{ + ApiVersion: "2020-01-01", + ModelName: "Second", + }, + } + assertChanges(t, expected, *actual) + assertContainsNoBreakingChanges(t, *actual) +} + +func TestDiff_CommonTypesModelRemoved(t *testing.T) { + initial := map[string]models.SDKModel{ + "First": {}, + "Second": {}, + } + updated := map[string]models.SDKModel{ + "First": {}, + } + actual, err := differ{}.changesForCommonTypesModels("2020-01-01", initial, updated) + if err != nil { + t.Fatalf(err.Error()) + } + expected := []changes.Change{ + changes.CommonTypesModelRemoved{ + ApiVersion: "2020-01-01", + ModelName: "Second", + }, + } + assertChanges(t, expected, *actual) + assertContainsBreakingChanges(t, *actual) +} + +func TestDiff_CommonTypesModelDiscriminatedParentTypeAdded(t *testing.T) { + initial := map[string]models.SDKModel{ + "First": { + ParentTypeName: nil, + }, + } + updated := map[string]models.SDKModel{ + "First": { + ParentTypeName: pointer.To("NewValue"), + }, + } + actual, err := differ{}.changesForCommonTypesModels("2020-01-01", initial, updated) + if err != nil { + t.Fatalf(err.Error()) + } + expected := []changes.Change{ + changes.ModelDiscriminatedParentTypeAdded{ + ServiceName: commonTypesServiceName, + ApiVersion: "2020-01-01", + ResourceName: commonTypesServiceName, + ModelName: "First", + NewParentModelName: "NewValue", + }, + } + assertChanges(t, expected, *actual) + assertContainsBreakingChanges(t, *actual) +} + +func TestDiff_CommonTypesModelDiscriminatedParentTypeChanged(t *testing.T) { + initial := map[string]models.SDKModel{ + "First": { + ParentTypeName: pointer.To("OldValue"), + }, + } + updated := map[string]models.SDKModel{ + "First": { + ParentTypeName: pointer.To("NewValue"), + }, + } + actual, err := differ{}.changesForCommonTypesModels("2020-01-01", initial, updated) + if err != nil { + t.Fatalf(err.Error()) + } + expected := []changes.Change{ + changes.ModelDiscriminatedParentTypeChanged{ + ServiceName: commonTypesServiceName, + ApiVersion: "2020-01-01", + ResourceName: commonTypesServiceName, + ModelName: "First", + OldParentModelName: "OldValue", + NewParentModelName: "NewValue", + }, + } + assertChanges(t, expected, *actual) + assertContainsBreakingChanges(t, *actual) +} + +func TestDiff_CommonTypesModelDiscriminatedParentTypeRemoved(t *testing.T) { + initial := map[string]models.SDKModel{ + "First": { + ParentTypeName: pointer.To("OldValue"), + }, + } + updated := map[string]models.SDKModel{ + "First": { + ParentTypeName: nil, + }, + } + actual, err := differ{}.changesForCommonTypesModels("2020-01-01", initial, updated) + if err != nil { + t.Fatalf(err.Error()) + } + expected := []changes.Change{ + changes.ModelDiscriminatedParentTypeRemoved{ + ServiceName: commonTypesServiceName, + ApiVersion: "2020-01-01", + ResourceName: commonTypesServiceName, + ModelName: "First", + OldParentModelName: "OldValue", + }, + } + assertChanges(t, expected, *actual) + assertContainsBreakingChanges(t, *actual) +} + +func TestDiff_CommonTypesModelDiscriminatedFieldNameContainingDiscriminatedValueChanged(t *testing.T) { + initial := map[string]models.SDKModel{ + "First": { + FieldNameContainingDiscriminatedValue: pointer.To("OldValue"), + }, + } + updated := map[string]models.SDKModel{ + "First": { + FieldNameContainingDiscriminatedValue: pointer.To("NewValue"), + }, + } + actual, err := differ{}.changesForCommonTypesModels("2020-01-01", initial, updated) + if err != nil { + t.Fatalf(err.Error()) + } + expected := []changes.Change{ + changes.ModelDiscriminatedTypeHintInChanged{ + ServiceName: commonTypesServiceName, + ApiVersion: "2020-01-01", + ResourceName: commonTypesServiceName, + ModelName: "First", + OldValue: "OldValue", + NewValue: "NewValue", + }, + } + assertChanges(t, expected, *actual) + assertContainsBreakingChanges(t, *actual) +} + +func TestDiff_CommonTypesModelDiscriminatedDiscriminatedValueChanged(t *testing.T) { + initial := map[string]models.SDKModel{ + "First": { + DiscriminatedValue: pointer.To("OldValue"), + }, + } + updated := map[string]models.SDKModel{ + "First": { + DiscriminatedValue: pointer.To("NewValue"), + }, + } + actual, err := differ{}.changesForCommonTypesModels("2020-01-01", initial, updated) + if err != nil { + t.Fatalf(err.Error()) + } + expected := []changes.Change{ + changes.ModelDiscriminatedTypeValueChanged{ + ServiceName: commonTypesServiceName, + ApiVersion: "2020-01-01", + ResourceName: commonTypesServiceName, + ModelName: "First", + OldValue: "OldValue", + NewValue: "NewValue", + }, + } + assertChanges(t, expected, *actual) + assertContainsBreakingChanges(t, *actual) +} diff --git a/tools/data-api-differ/internal/differ/differ_common_types_test.go b/tools/data-api-differ/internal/differ/differ_common_types_test.go new file mode 100644 index 00000000000..1f6c351e435 --- /dev/null +++ b/tools/data-api-differ/internal/differ/differ_common_types_test.go @@ -0,0 +1,181 @@ +package differ + +import ( + "testing" + + "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" + "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" +) + +func TestDiff_CommonTypesAdded_WithNestedDetails(t *testing.T) { + initial := map[string]models.CommonTypes{} + updated := map[string]models.CommonTypes{ + "2020-01-01": { + Constants: map[string]models.SDKConstant{ + "SomeConst": { + Type: models.StringSDKConstantType, + Values: map[string]string{ + "First": "first", + }, + }, + }, + Models: map[string]models.SDKModel{ + "SomeModel": { + Fields: map[string]models.SDKField{ + "Example": { + Required: true, + JsonName: "example", + ObjectDefinition: models.SDKObjectDefinition{ + Type: models.StringSDKObjectDefinitionType, + }, + }, + }, + }, + }, + }, + } + actual, err := differ{}.changesForCommonTypes(initial, updated, true) + if err != nil { + t.Fatalf(err.Error()) + } + expected := []changes.Change{ + changes.CommonTypesApiVersionAdded{ + ApiVersion: "2020-01-01", + }, + changes.CommonTypesConstantAdded{ + ApiVersion: "2020-01-01", + ConstantName: "SomeConst", + ConstantType: models.StringSDKConstantType, + KeysAndValues: map[string]string{ + "First": "first", + }, + }, + changes.CommonTypesModelAdded{ + ApiVersion: "2020-01-01", + ModelName: "SomeModel", + }, + } + assertChanges(t, expected, *actual) + assertContainsNoBreakingChanges(t, *actual) +} + +func TestDiff_CommonTypesAdded_WithoutNestedDetails(t *testing.T) { + initial := map[string]models.CommonTypes{} + updated := map[string]models.CommonTypes{ + "2020-01-01": { + Constants: map[string]models.SDKConstant{ + "SomeConst": { + Type: models.StringSDKConstantType, + Values: map[string]string{ + "First": "first", + }, + }, + }, + Models: map[string]models.SDKModel{ + "SomeModel": { + Fields: map[string]models.SDKField{ + "Example": { + Required: true, + JsonName: "example", + ObjectDefinition: models.SDKObjectDefinition{ + Type: models.StringSDKObjectDefinitionType, + }, + }, + }, + }, + }, + }, + } + actual, err := differ{}.changesForCommonTypes(initial, updated, false) + if err != nil { + t.Fatalf(err.Error()) + } + expected := []changes.Change{ + changes.CommonTypesApiVersionAdded{ + ApiVersion: "2020-01-01", + }, + } + assertChanges(t, expected, *actual) + assertContainsNoBreakingChanges(t, *actual) +} + +func TestDiff_CommonTypesRemoved_WithNestedDetails(t *testing.T) { + initial := map[string]models.CommonTypes{ + "2020-01-01": { + Constants: map[string]models.SDKConstant{ + "SomeConst": { + Type: models.StringSDKConstantType, + Values: map[string]string{ + "First": "first", + }, + }, + }, + Models: map[string]models.SDKModel{ + "SomeModel": { + Fields: map[string]models.SDKField{ + "Example": { + Required: true, + JsonName: "example", + ObjectDefinition: models.SDKObjectDefinition{ + Type: models.StringSDKObjectDefinitionType, + }, + }, + }, + }, + }, + }, + } + updated := map[string]models.CommonTypes{} + actual, err := differ{}.changesForCommonTypes(initial, updated, true) + if err != nil { + t.Fatalf(err.Error()) + } + expected := []changes.Change{ + changes.CommonTypesApiVersionRemoved{ + ApiVersion: "2020-01-01", + }, + // NOTE: the Constant and Model being removed won't be surfaced since this is a removal of an APIVersion + } + assertChanges(t, expected, *actual) + assertContainsBreakingChanges(t, *actual) +} + +func TestDiff_CommonTypesRemoved_WithoutNestedDetails(t *testing.T) { + initial := map[string]models.CommonTypes{ + "2020-01-01": { + Constants: map[string]models.SDKConstant{ + "SomeConst": { + Type: models.StringSDKConstantType, + Values: map[string]string{ + "First": "first", + }, + }, + }, + Models: map[string]models.SDKModel{ + "SomeModel": { + Fields: map[string]models.SDKField{ + "Example": { + Required: true, + JsonName: "example", + ObjectDefinition: models.SDKObjectDefinition{ + Type: models.StringSDKObjectDefinitionType, + }, + }, + }, + }, + }, + }, + } + updated := map[string]models.CommonTypes{} + actual, err := differ{}.changesForCommonTypes(initial, updated, false) + if err != nil { + t.Fatalf(err.Error()) + } + expected := []changes.Change{ + changes.CommonTypesApiVersionRemoved{ + ApiVersion: "2020-01-01", + }, + } + assertChanges(t, expected, *actual) + assertContainsBreakingChanges(t, *actual) +} diff --git a/tools/data-api-differ/internal/differ/differ_constants.go b/tools/data-api-differ/internal/differ/differ_constants.go index 0c29d6585a1..248e5be6c43 100644 --- a/tools/data-api-differ/internal/differ/differ_constants.go +++ b/tools/data-api-differ/internal/differ/differ_constants.go @@ -5,8 +5,6 @@ package differ import ( "fmt" - "sort" - "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" "github.com/hashicorp/pandora/tools/data-api-differ/internal/log" "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" @@ -15,7 +13,7 @@ import ( // changesForConstants determines the changes between the different Constants within the provided API Resource. func (d differ) changesForConstants(serviceName, apiVersion, apiResource string, initial, updated map[string]models.SDKConstant) []changes.Change { output := make([]changes.Change, 0) - constantNames := d.uniqueConstantNames(initial, updated) + constantNames := uniqueKeys(initial, updated) for _, constantName := range constantNames { log.Logger.Trace(fmt.Sprintf("Detecting changes in Constant %q..", constantName)) changesForConstant := d.changesForConstant(serviceName, apiVersion, apiResource, constantName, initial, updated) @@ -71,7 +69,7 @@ func (d differ) changesForConstant(serviceName, apiVersion, apiResource, constan } } - keys := d.uniqueKeys(oldData.Values, updatedData.Values) + keys := uniqueKeys(oldData.Values, updatedData.Values) for _, key := range keys { log.Logger.Trace(fmt.Sprintf("Detecting changes in Constant Key %q..", key)) oldValue, oldContainsKey := oldData.Values[key] @@ -120,21 +118,3 @@ func (d differ) changesForConstant(serviceName, apiVersion, apiResource, constan return output } - -// uniqueConstantNames returns a unique, sorted list of Constant Names from the keys of initial and updated. -func (d differ) uniqueConstantNames(initial, updated map[string]models.SDKConstant) []string { - uniqueNames := make(map[string]struct{}) - for name := range initial { - uniqueNames[name] = struct{}{} - } - for name := range updated { - uniqueNames[name] = struct{}{} - } - - output := make([]string, 0) - for k := range uniqueNames { - output = append(output, k) - } - sort.Strings(output) - return output -} diff --git a/tools/data-api-differ/internal/differ/differ_fields.go b/tools/data-api-differ/internal/differ/differ_fields.go index 81be7c76ab9..be1a1905af2 100644 --- a/tools/data-api-differ/internal/differ/differ_fields.go +++ b/tools/data-api-differ/internal/differ/differ_fields.go @@ -5,8 +5,6 @@ package differ import ( "fmt" - "sort" - "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" "github.com/hashicorp/pandora/tools/data-api-differ/internal/log" "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" @@ -104,7 +102,7 @@ func (d differ) changesForField(serviceName, apiVersion, apiResource, modelName, // changesForFields determines the changes between the initial and updated Fields within the specified Model. func (d differ) changesForFields(serviceName, apiVersion, apiResource, modelName string, initial, updated map[string]models.SDKField) (*[]changes.Change, error) { output := make([]changes.Change, 0) - fieldNames := d.uniqueFieldNames(initial, updated) + fieldNames := uniqueKeys(initial, updated) for _, fieldName := range fieldNames { log.Logger.Trace(fmt.Sprintf("Detecting changes in Field %q..", fieldName)) changesForField, err := d.changesForField(serviceName, apiVersion, apiResource, modelName, fieldName, initial, updated) @@ -115,21 +113,3 @@ func (d differ) changesForFields(serviceName, apiVersion, apiResource, modelName } return &output, nil } - -// uniqueFieldNames returns a unique, sorted list of Field Names from the keys of initial and updated. -func (d differ) uniqueFieldNames(initial, updated map[string]models.SDKField) []string { - uniqueNames := make(map[string]struct{}) - for name := range initial { - uniqueNames[name] = struct{}{} - } - for name := range updated { - uniqueNames[name] = struct{}{} - } - - output := make([]string, 0) - for k := range uniqueNames { - output = append(output, k) - } - sort.Strings(output) - return output -} diff --git a/tools/data-api-differ/internal/differ/differ_helpers.go b/tools/data-api-differ/internal/differ/differ_helpers.go index af55895122d..6766612e1e6 100644 --- a/tools/data-api-differ/internal/differ/differ_helpers.go +++ b/tools/data-api-differ/internal/differ/differ_helpers.go @@ -20,8 +20,8 @@ func (d differ) stringifySDKOperationOptionObjectDefinition(input models.SDKOper return helpers.GolangTypeForSDKOperationOptionObjectDefinition(input) } -// uniqueConstantNames returns a unique, sorted list of Keys from initial and updated. -func (d differ) uniqueKeys(initial, updated map[string]string) []string { +// uniqueKeys returns a unique, sorted list of Keys from initial and updated. +func uniqueKeys[T any](initial, updated map[string]T) []string { uniqueNames := make(map[string]struct{}) for name := range initial { uniqueNames[name] = struct{}{} diff --git a/tools/data-api-differ/internal/differ/differ_models.go b/tools/data-api-differ/internal/differ/differ_models.go index d8278ea6d04..00965ed0035 100644 --- a/tools/data-api-differ/internal/differ/differ_models.go +++ b/tools/data-api-differ/internal/differ/differ_models.go @@ -5,8 +5,6 @@ package differ import ( "fmt" - "sort" - "github.com/hashicorp/go-azure-helpers/lang/pointer" "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" "github.com/hashicorp/pandora/tools/data-api-differ/internal/log" @@ -16,7 +14,7 @@ import ( // changesForModels determines the changes between the initial and updated Models within the specified API Resource. func (d differ) changesForModels(serviceName, apiVersion, apiResource string, initial, updated map[string]models.SDKModel) (*[]changes.Change, error) { output := make([]changes.Change, 0) - modelNames := d.uniqueModelNames(initial, updated) + modelNames := uniqueKeys(initial, updated) for _, modelName := range modelNames { log.Logger.Trace(fmt.Sprintf("Detecting changes in Model %q..", modelName)) changesForModel, err := d.changesForModel(serviceName, apiVersion, apiResource, modelName, initial, updated) @@ -145,21 +143,3 @@ func (d differ) discriminatorChangesForModel(serviceName, apiVersion, apiResourc return output } - -// uniqueModelNames returns a unique, sorted list of Model Names from the keys of initial and updated. -func (d differ) uniqueModelNames(initial, updated map[string]models.SDKModel) []string { - uniqueNames := make(map[string]struct{}) - for name := range initial { - uniqueNames[name] = struct{}{} - } - for name := range updated { - uniqueNames[name] = struct{}{} - } - - output := make([]string, 0) - for k := range uniqueNames { - output = append(output, k) - } - sort.Strings(output) - return output -} diff --git a/tools/data-api-differ/internal/differ/differ_operations.go b/tools/data-api-differ/internal/differ/differ_operations.go index 83d5d63b4c1..53fd1880c4e 100644 --- a/tools/data-api-differ/internal/differ/differ_operations.go +++ b/tools/data-api-differ/internal/differ/differ_operations.go @@ -19,7 +19,7 @@ import ( // changesForOperations determines the changes between the initial and updated Operations within the specified API Resource. func (d differ) changesForOperations(serviceName, apiVersion, apiResource string, initial, updated map[string]models.SDKOperation, initialResourceIds, updatedResourceIds map[string]models.ResourceID) (*[]changes.Change, error) { output := make([]changes.Change, 0) - operationNames := d.uniqueOperationNames(initial, updated) + operationNames := uniqueKeys(initial, updated) for _, operationName := range operationNames { log.Logger.Trace(fmt.Sprintf("Detecting changes in Operation %q..", operationName)) changesForOperation, err := d.changesForOperation(serviceName, apiVersion, apiResource, operationName, initial, updated, initialResourceIds, updatedResourceIds) @@ -486,8 +486,8 @@ func (d differ) optionsMatch(initial, updated map[string]models.SDKOperationOpti if err != nil { return nil, fmt.Errorf("stringifying the Updated Operation Options: %+v", err) } - uniqueKeys := d.uniqueKeys(*initialStringified, *updatedStringified) - for _, key := range uniqueKeys { + uniqKeys := uniqueKeys(*initialStringified, *updatedStringified) + for _, key := range uniqKeys { initialVal, isInInitial := (*initialStringified)[key] if !isInInitial { return pointer.To(false), nil @@ -568,21 +568,3 @@ func (d differ) uriForOperation(input models.SDKOperation, resourceIds map[strin return out } - -// uniqueOperationNames returns a unique, sorted list of Operation Names from the keys of initial and updated. -func (d differ) uniqueOperationNames(initial, updated map[string]models.SDKOperation) []string { - uniqueNames := make(map[string]struct{}) - for name := range initial { - uniqueNames[name] = struct{}{} - } - for name := range updated { - uniqueNames[name] = struct{}{} - } - - output := make([]string, 0) - for k := range uniqueNames { - output = append(output, k) - } - sort.Strings(output) - return output -} diff --git a/tools/data-api-differ/internal/differ/differ_resource_ids.go b/tools/data-api-differ/internal/differ/differ_resource_ids.go index b40b729debc..de903db34fa 100644 --- a/tools/data-api-differ/internal/differ/differ_resource_ids.go +++ b/tools/data-api-differ/internal/differ/differ_resource_ids.go @@ -16,7 +16,7 @@ import ( func (d differ) changesForResourceIds(serviceName, apiVersion, apiResource string, initial, updated map[string]models.ResourceID) []changes.Change { output := make([]changes.Change, 0) - resourceIdNames := d.uniqueResourceIdNames(initial, updated) + resourceIdNames := uniqueKeys(initial, updated) for _, resourceIdName := range resourceIdNames { log.Logger.Trace(fmt.Sprintf("Detecting changes in Resource ID %q..", resourceIdName)) changesForResourceId := d.changesForResourceId(serviceName, apiVersion, apiResource, resourceIdName, initial, updated) @@ -206,21 +206,3 @@ func (d differ) staticIdentifiersInResourceIdSegments(input []models.ResourceIDS sort.Strings(output) return output } - -// uniqueResourceIdNames returns a unique, sorted list of Resource ID Names from the keys of initial and updated. -func (d differ) uniqueResourceIdNames(initial, updated map[string]models.ResourceID) []string { - uniqueNames := make(map[string]struct{}) - for name := range initial { - uniqueNames[name] = struct{}{} - } - for name := range updated { - uniqueNames[name] = struct{}{} - } - - output := make([]string, 0) - for k := range uniqueNames { - output = append(output, k) - } - sort.Strings(output) - return output -} diff --git a/tools/data-api-differ/internal/differ/differ_services.go b/tools/data-api-differ/internal/differ/differ_services.go index fca44bd3fb3..42ef23b8ab0 100644 --- a/tools/data-api-differ/internal/differ/differ_services.go +++ b/tools/data-api-differ/internal/differ/differ_services.go @@ -5,8 +5,6 @@ package differ import ( "fmt" - "sort" - "github.com/hashicorp/pandora/tools/data-api-differ/internal/changes" "github.com/hashicorp/pandora/tools/data-api-differ/internal/log" "github.com/hashicorp/pandora/tools/data-api-sdk/v1/models" @@ -17,7 +15,7 @@ func (d differ) changesForServices(initial, updated map[string]models.Service, i output := make([]changes.Change, 0) // first pull out a unique list of Service names log.Logger.Info("Identifying a unique list of Service Names..") - serviceNames := d.uniqueServiceNames(initial, updated) + serviceNames := uniqueKeys(initial, updated) for _, serviceName := range serviceNames { log.Logger.Info(fmt.Sprintf("Detecting changes in Service %q..", serviceName)) changesForService, err := d.changesForService(serviceName, initial, updated, includeNestedChangesWhenNew) @@ -69,21 +67,3 @@ func (d differ) changesForService(serviceName string, initial, updated map[strin return &output, nil } - -// uniqueServiceNames returns a unique, ordered list of Service Names from the initial and updated set of Services. -func (d differ) uniqueServiceNames(initial, updated map[string]models.Service) []string { - uniqueNames := make(map[string]struct{}) - for name := range initial { - uniqueNames[name] = struct{}{} - } - for name := range updated { - uniqueNames[name] = struct{}{} - } - - output := make([]string, 0) - for k := range uniqueNames { - output = append(output, k) - } - sort.Strings(output) - return output -} diff --git a/tools/data-api-differ/internal/views/markdown.go b/tools/data-api-differ/internal/views/markdown.go index 048bc109dea..8c9c15b53df 100644 --- a/tools/data-api-differ/internal/views/markdown.go +++ b/tools/data-api-differ/internal/views/markdown.go @@ -16,6 +16,69 @@ import ( // renderChangeToMarkdown renders a summary of this change in Markdown func renderChangeToMarkdown(input changes.Change) (*string, error) { switch input.(type) { + // CommonTypes + case changes.CommonTypesApiVersionAdded: + { + v := input.(changes.CommonTypesApiVersionAdded) + line := fmt.Sprintf("**New CommonTypes API Version:** `%s`.", v.ApiVersion) + return trimSpaceAround(line) + } + case changes.CommonTypesApiVersionRemoved: + { + v := input.(changes.CommonTypesApiVersionRemoved) + line := fmt.Sprintf("**Removed CommonTypes API Version:** `%s`.", v.ApiVersion) + return trimSpaceAround(line) + } + case changes.CommonTypesConstantAdded: + { + v := input.(changes.CommonTypesConstantAdded) + keysAndValues := strings.Join(sortConstantKeysAndValues(v.KeysAndValues), ", ") + line := fmt.Sprintf("**New CommonTypes Constant:** `%s` (Type `%s`) in `%s`. Possible Values: %s.", v.ConstantName, v.ConstantType, v.ApiVersion, keysAndValues) + return trimSpaceAround(line) + } + case changes.CommonTypesConstantKeyValueAdded: + { + v := input.(changes.CommonTypesConstantKeyValueAdded) + line := fmt.Sprintf("**New Key/Value for CommonTypes Constant:** `%s` - Key `%s` / Value `%s` in `%s`.", v.ConstantName, v.ConstantKey, v.ConstantValue, v.ApiVersion) + return trimSpaceAround(line) + } + case changes.CommonTypesConstantKeyValueChanged: + { + v := input.(changes.CommonTypesConstantKeyValueChanged) + line := fmt.Sprintf("**Updated Value for CommonTypes Constant Key:** Constant `%s` Key `%s` - Old Value `%s` / New Value `%s` in `%s`.", v.ConstantName, v.ConstantKey, v.OldConstantValue, v.NewConstantValue, v.ApiVersion) + return trimSpaceAround(line) + } + case changes.CommonTypesConstantKeyValueRemoved: + { + v := input.(changes.CommonTypesConstantKeyValueRemoved) + line := fmt.Sprintf("**Removed Key/Value for CommonTypes Constant:** `%s` - Key `%s` / Value `%s` in `%s`.", v.ConstantName, v.ConstantKey, v.ConstantValue, v.ApiVersion) + return trimSpaceAround(line) + } + case changes.CommonTypesConstantRemoved: + { + // intentionally not outputting the old values for now, but they're on the object if this is useful + v := input.(changes.CommonTypesConstantRemoved) + line := fmt.Sprintf("**Removed CommonTypes Constant:** `%s` (Type `%s`) in `%s`.", v.ConstantName, v.ConstantType, v.ApiVersion) + return trimSpaceAround(line) + } + case changes.CommonTypesConstantTypeChanged: + { + v := input.(changes.CommonTypesConstantTypeChanged) + line := fmt.Sprintf("**Updated Type for CommonTypes Constant:** `%s` - Old Type `%s` / New Type `%s` in `%s`.", v.ConstantName, v.OldType, v.NewType, v.ApiVersion) + return trimSpaceAround(line) + } + case changes.CommonTypesModelAdded: + { + v := input.(changes.CommonTypesModelAdded) + line := fmt.Sprintf("**CommonTypes Model Added:** `%s` in `%s`.", v.ModelName, v.ApiVersion) + return trimSpaceAround(line) + } + case changes.CommonTypesModelRemoved: + { + v := input.(changes.CommonTypesModelRemoved) + line := fmt.Sprintf("**CommonTypes Model Removed:** `%s` in `%s`.", v.ModelName, v.ApiVersion) + return trimSpaceAround(line) + } // Services case changes.ServiceAdded: @@ -106,7 +169,6 @@ func renderChangeToMarkdown(input changes.Change) (*string, error) { line := fmt.Sprintf("**Field Added:** `%s` to Model `%s` in `%s@%s/%s`.", v.FieldName, v.ModelName, v.ServiceName, v.ApiVersion, v.ResourceName) return trimSpaceAround(line) } - case changes.FieldIsNowOptional: { v := input.(changes.FieldIsNowOptional) @@ -139,6 +201,8 @@ func renderChangeToMarkdown(input changes.Change) (*string, error) { } // Models + + // Models case changes.ModelAdded: { v := input.(changes.ModelAdded) @@ -328,49 +392,43 @@ func renderChangeToMarkdown(input changes.Change) (*string, error) { return trimSpaceAround(line) } - // Resource IDs + // Resource IDs case changes.ResourceIdAdded: { v := input.(changes.ResourceIdAdded) line := fmt.Sprintf("**New Resource ID:** `%s` (ID `%s`) in `%s@%s/%s`.", v.ResourceIdName, v.ResourceIdValue, v.ServiceName, v.ApiVersion, v.ResourceName) return trimSpaceAround(line) } - case changes.ResourceIdCommonIdAdded: { v := input.(changes.ResourceIdCommonIdAdded) line := fmt.Sprintf("**Resource ID is now a Common ID:** `%s` (Alias `%s` / ID `%s`) in `%s@%s/%s`.", v.ResourceIdName, v.CommonAliasName, v.ResourceIdValue, v.ServiceName, v.ApiVersion, v.ResourceName) return trimSpaceAround(line) } - case changes.ResourceIdCommonIdChanged: { v := input.(changes.ResourceIdCommonIdChanged) line := fmt.Sprintf("**Resource ID has changed it's Common ID:** `%s` (was `%s` now `%s`) in `%s@%s/%s`.", v.ResourceIdName, v.OldCommonAliasName, v.NewCommonAliasName, v.ServiceName, v.ApiVersion, v.ResourceName) return trimSpaceAround(line) } - case changes.ResourceIdCommonIdRemoved: { v := input.(changes.ResourceIdCommonIdRemoved) line := fmt.Sprintf("**Resource ID is no longer a Common ID:** `%s` (Alias `%s` / ID `%s`) in `%s@%s/%s`.", v.ResourceIdName, v.CommonAliasName, v.ResourceIdValue, v.ServiceName, v.ApiVersion, v.ResourceName) return trimSpaceAround(line) } - case changes.ResourceIdRemoved: { v := input.(changes.ResourceIdRemoved) line := fmt.Sprintf("**Removed Resource ID:** `%s` (ID `%s`) in `%s@%s/%s`.", v.ResourceIdName, v.ResourceIdValue, v.ServiceName, v.ApiVersion, v.ResourceName) return trimSpaceAround(line) } - case changes.ResourceIdSegmentChangedValue: { v := input.(changes.ResourceIdSegmentChangedValue) line := fmt.Sprintf("**Resource ID Segment (Index %d) Changed Value:** `%s` (was `%s` now `%s`) in `%s@%s/%s`.", v.SegmentIndex, v.ResourceIdName, v.OldValue, v.NewValue, v.ServiceName, v.ApiVersion, v.ResourceName) return trimSpaceAround(line) } - case changes.ResourceIdSegmentsChangedLength: { v := input.(changes.ResourceIdSegmentsChangedLength)