Skip to content

Commit

Permalink
Merge pull request #3235 from hashicorp/f/importer-v2-api-definitions…
Browse files Browse the repository at this point in the history
…-metadata

tools/importer-rest-api-specs: updating the `metadata` file to include the SourceData and SourceInformation
  • Loading branch information
tombuildsstuff authored Oct 25, 2023
2 parents 6529b64 + 5b450d7 commit 49112b2
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ type ApiVersionDefinition struct {
// Generate specifies whether this API Version should be generated or not.
Generate bool `json:"generate"`

// Source specifies where the source data for this API version came from.
Source ApiDefinitionsSource `json:"source"` // TODO: move this into the MetaData file?

// Resources specifies a list of Api Resource names that exist within this API version.
Resources []string `json:"resources"`
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ package models

// MetaData contains Meta Data about this
type MetaData struct {
// TODO: the license information could make sense to go in here, since all items within a
// directory should be under the same license
// DataSource specifies the type of Data that this Source is related to
// for example `AzureResourceManager`. This allows multiple directories
// to be used to populate the same Data Source (for example, auto-generated
// and handwritten) and then coalesced together.
DataSource DataSource `json:"dataSource"`

// SourceInformation specifies where the data within this directory was sourced.
SourceInformation ApiDefinitionsSource `json:"sourceInformation"`

// GitRevision specified the Git Revision (SHA) of the Repository
// where this data has been sourced from.
Expand All @@ -12,6 +18,16 @@ type MetaData struct {
GitRevision *string `json:"gitRevision"`
}

type DataSource string

const (
// AzureResourceManagerDataSource specifies that this Data is related to Azure Resource Manager.
AzureResourceManagerDataSource DataSource = "AzureResourceManager"

// MicrosoftGraphDataSource specifies that this Data is for Microsoft Graph.
MicrosoftGraphDataSource DataSource = "MicrosoftGraph"
)

type ApiDefinitionsSource string

const (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import (

func OutputMetaData(workingDirectory, swaggerGitSha string) error {
metaData := dataApiModels.MetaData{
GitRevision: pointer.To(swaggerGitSha),
DataSource: dataApiModels.AzureResourceManagerDataSource,
SourceInformation: dataApiModels.AzureRestApiSpecsRepositoryApiDefinitionsSource,
GitRevision: pointer.To(swaggerGitSha),
}

data, err := json.MarshalIndent(&metaData, "", "\t")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ func buildApiVersionDefinition(apiVersion string, isPreview bool, resources map[
versionDefinition := dataApiModels.ApiVersionDefinition{
ApiVersion: apiVersion,
IsPreview: isPreview,
Source: dataApiModels.AzureRestApiSpecsRepositoryApiDefinitionsSource,
Generate: true,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func codeForModel(modelName string, model importerModels.ModelDetails, parentMod
}

dataApiModel := dataApiModels.Model{
Name: modelName,
Fields: *fields,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,69 +12,43 @@ import (
"github.com/hashicorp/pandora/tools/sdk/resourcemanager"
)

func codeForOperation(operationName string, operation importerModels.OperationDetails, knownConstants map[string]resourcemanager.ConstantDetails, knownModels map[string]importerModels.ModelDetails) ([]byte, error) {
contentType := ""
if !strings.Contains(strings.ToLower(operation.ContentType), "application/json") {
contentType = operation.ContentType
func codeForOperation(operationName string, input importerModels.OperationDetails, knownConstants map[string]resourcemanager.ConstantDetails, knownModels map[string]importerModels.ModelDetails) ([]byte, error) {
output := dataApiModels.Operation{
Name: operationName,
ContentType: input.ContentType,
ExpectedStatusCodes: input.ExpectedStatusCodes,
FieldContainingPaginationDetails: input.FieldContainingPaginationDetails,
LongRunning: input.LongRunning,
HTTPMethod: strings.ToUpper(input.Method),
ResourceIdName: input.ResourceIdName,
UriSuffix: input.UriSuffix,
}

statusCodes := make([]int, 0)
if usesNonDefaultStatusCodes(operation) {
for _, sc := range operation.ExpectedStatusCodes {
statusCodes = append(statusCodes, sc)
if input.RequestObject != nil {
requestObject, err := mapObjectDefinition(input.RequestObject, knownConstants, knownModels)
if err != nil {
return nil, fmt.Errorf("mapping the request object definition: %+v", err)
}
sort.Ints(statusCodes)
}

longRunning := false
if operation.LongRunning {
// TODO: we can use the `LongRunning` operation base types too
longRunning = true
}

resourceId := ""
if operation.ResourceIdName != nil {
resourceId = *operation.ResourceIdName
}

uriSuffix := ""
if operation.UriSuffix != nil {
uriSuffix = *operation.UriSuffix
output.RequestObject = requestObject
}

responseObject, err := mapObjectDefinition(operation.ResponseObject, knownConstants, knownModels)
if err != nil {
return nil, fmt.Errorf("mapping the object definition: %+v", err)
}

requestObject, err := mapObjectDefinition(operation.RequestObject, knownConstants, knownModels)
if err != nil {
return nil, fmt.Errorf("mapping the object definition: %+v", err)
}

op := dataApiModels.Operation{
Name: operationName,
ContentType: contentType,
ExpectedStatusCodes: statusCodes,
FieldContainingPaginationDetails: operation.FieldContainingPaginationDetails,
LongRunning: longRunning,
HTTPMethod: strings.ToUpper(operation.Method),
ResourceIdName: pointer.To(resourceId),
RequestObject: responseObject,
ResponseObject: requestObject,
UriSuffix: pointer.To(uriSuffix),
if input.ResponseObject != nil {
responseObject, err := mapObjectDefinition(input.ResponseObject, knownConstants, knownModels)
if err != nil {
return nil, fmt.Errorf("mapping the response object definition: %+v", err)
}
output.ResponseObject = responseObject
}

if len(operation.Options) > 0 {
if len(input.Options) > 0 {
options := make([]dataApiModels.Option, 0)
sortedOptionsKeys := make([]string, 0)
for k := range operation.Options {
for k := range input.Options {
sortedOptionsKeys = append(sortedOptionsKeys, k)
}
sort.Strings(sortedOptionsKeys)

for _, optionName := range sortedOptionsKeys {
optionDetails := operation.Options[optionName]
optionDetails := input.Options[optionName]

if optionDetails.ObjectDefinition == nil {
return nil, fmt.Errorf("missing object definition")
Expand All @@ -100,47 +74,17 @@ func codeForOperation(operationName string, operation importerModels.OperationDe

options = append(options, option)
}
op.Options = pointer.To(options)
output.Options = pointer.To(options)
}

data, err := json.MarshalIndent(op, "", " ")
data, err := json.MarshalIndent(output, "", " ")
if err != nil {
return nil, err
}

return data, nil
}

func usesNonDefaultStatusCodes(operation importerModels.OperationDetails) bool {
defaultStatusCodes := map[string][]int{
"get": {200},
"post": {200, 201},
"put": {200, 201},
"delete": {200, 201},
"patch": {200, 201},
}
expected, ok := defaultStatusCodes[strings.ToLower(operation.Method)]
if !ok {
// potentially an unsupported use-case but fine for now
return true
}

if len(expected) != len(operation.ExpectedStatusCodes) {
return true
}

sort.Ints(expected)
sort.Ints(operation.ExpectedStatusCodes)
for i, ev := range expected {
av := operation.ExpectedStatusCodes[i]
if ev != av {
return true
}
}

return false
}

var internalObjectDefinitionsToOptionObjectDefinitionTypes = map[importerModels.ObjectDefinitionType]dataApiModels.OptionObjectDefinitionType{
importerModels.ObjectDefinitionBoolean: dataApiModels.BooleanOptionObjectDefinitionType,
importerModels.ObjectDefinitionCsv: dataApiModels.CsvOptionObjectDefinitionType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,6 @@ func mapResourceIdSegment(input resourcemanager.ResourceIdSegment) (*dataApiMode
}

if input.Type == resourcemanager.SubscriptionIdSegment {
if input.FixedValue == nil {
return nil, fmt.Errorf("static segment type with missing fixed value: %+v", input)
}
return &dataApiModels.ResourceIdSegment{
Type: dataApiModels.SubscriptionIdResourceIdSegmentType,
Name: input.Name,
Expand Down

0 comments on commit 49112b2

Please sign in to comment.