in cli/bpmetadata/cmd.go [193:280]
func CreateBlueprintMetadata(bpPath string, bpMetadataObj *BlueprintMetadata) (*BlueprintMetadata, error) {
// Verify that readme is present.
readmeContent, err := os.ReadFile(path.Join(bpPath, readmeFileName))
if err != nil {
return nil, fmt.Errorf("blueprint readme markdown is missing, create one using https://tinyurl.com/tf-mod-readme | error: %w", err)
}
// verify that the blueprint path is valid & get repo details
getRepoDetailsByPath(bpPath, &repoDetails, readmeContent)
if repoDetails.ModuleName == "" && !mdFlags.quiet {
fmt.Printf("Provide a name for the blueprint at path [%s]: ", bpPath)
_, err := fmt.Scan(&repoDetails.ModuleName)
if err != nil {
fmt.Println("Unable to scan the name for the blueprint.")
}
}
if repoDetails.Source.URL == "" && !mdFlags.quiet {
fmt.Printf("Provide a URL for the blueprint source at path [%s]: ", bpPath)
_, err := fmt.Scan(&repoDetails.Source.URL)
if err != nil {
fmt.Println("Unable to scan the URL for the blueprint.")
}
}
// start creating blueprint metadata
bpMetadataObj.ApiVersion = metadataApiVersion
bpMetadataObj.Kind = metadataKind
if bpMetadataObj.Metadata == nil {
bpMetadataObj.Metadata = &ResourceTypeMeta{
Name: repoDetails.ModuleName,
Annotations: map[string]string{localConfigAnnotation: "true"},
}
}
if bpMetadataObj.Spec == nil {
bpMetadataObj.Spec = &BlueprintMetadataSpec{}
}
if bpMetadataObj.Spec.Info == nil {
bpMetadataObj.Spec.Info = &BlueprintInfo{}
}
// create blueprint info
err = bpMetadataObj.Spec.Info.create(bpPath, repoDetails, readmeContent)
if err != nil {
return nil, fmt.Errorf("error creating blueprint info: %w", err)
}
var existingInterfaces *BlueprintInterface
if bpMetadataObj.Spec.Interfaces == nil {
bpMetadataObj.Spec.Interfaces = &BlueprintInterface{}
} else {
existingInterfaces = proto.Clone(bpMetadataObj.Spec.Interfaces).(*BlueprintInterface)
}
// create blueprint interfaces i.e. variables & outputs
err = bpMetadataObj.Spec.Interfaces.create(bpPath)
if err != nil {
return nil, fmt.Errorf("error creating blueprint interfaces: %w", err)
}
// Merge existing connections (if any) into the newly generated interfaces
mergeExistingConnections(bpMetadataObj.Spec.Interfaces, existingInterfaces)
// Merge existing output types (if any) into the newly generated interfaces
mergeExistingOutputTypes(bpMetadataObj.Spec.Interfaces, existingInterfaces)
// get blueprint requirements
rolesCfgPath := path.Join(repoDetails.Source.BlueprintRootPath, tfRolesFileName)
svcsCfgPath := path.Join(repoDetails.Source.BlueprintRootPath, tfServicesFileName)
versionsCfgPath := path.Join(bpPath, tfVersionsFileName)
requirements, err := getBlueprintRequirements(rolesCfgPath, svcsCfgPath, versionsCfgPath)
if err != nil {
Log.Info("skipping blueprint requirements since roles and/or services configurations were not found as per https://tinyurl.com/tf-iam and https://tinyurl.com/tf-services")
} else {
bpMetadataObj.Spec.Requirements = requirements
}
if bpMetadataObj.Spec.Content == nil {
bpMetadataObj.Spec.Content = &BlueprintContent{}
}
// create blueprint content i.e. documentation, icons, etc.
bpMetadataObj.Spec.Content.create(bpPath, repoDetails.Source.BlueprintRootPath, readmeContent)
return bpMetadataObj, nil
}