cli/azd/pkg/project/project_config.go (79 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. package project import ( "context" "fmt" "github.com/azure/azure-dev/cli/azd/pkg/cloud" "github.com/azure/azure-dev/cli/azd/pkg/ext" "github.com/azure/azure-dev/cli/azd/pkg/infra/provisioning" "github.com/azure/azure-dev/cli/azd/pkg/osutil" "github.com/azure/azure-dev/cli/azd/pkg/platform" "github.com/azure/azure-dev/cli/azd/pkg/state" "github.com/azure/azure-dev/cli/azd/pkg/workflow" ) // ProjectConfig is the top level object serialized into an azure.yaml file. // When changing project structure, make sure to update the JSON schema file for azure.yaml (<workspace // root>/schemas/vN.M/azure.yaml.json). type ProjectConfig struct { // Metadata that specifies the schema version. // // This is currently only used during [Save] to write the file schema annotation for intellisense. // This should include the "v" prefix used in official version numbers. MetaSchemaVersion string `yaml:"-"` RequiredVersions *RequiredVersions `yaml:"requiredVersions,omitempty"` Name string `yaml:"name"` ResourceGroupName osutil.ExpandableString `yaml:"resourceGroup,omitempty"` Path string `yaml:"-"` Metadata *ProjectMetadata `yaml:"metadata,omitempty"` Services map[string]*ServiceConfig `yaml:"services,omitempty"` Infra provisioning.Options `yaml:"infra,omitempty"` Pipeline PipelineOptions `yaml:"pipeline,omitempty"` Hooks HooksConfig `yaml:"hooks,omitempty"` State *state.Config `yaml:"state,omitempty"` Platform *platform.Config `yaml:"platform,omitempty"` Workflows workflow.WorkflowMap `yaml:"workflows,omitempty"` Cloud *cloud.Config `yaml:"cloud,omitempty"` Resources map[string]*ResourceConfig `yaml:"resources,omitempty"` *ext.EventDispatcher[ProjectLifecycleEventArgs] `yaml:"-"` } // RequiredVersions contains information about what versions of tools this project requires. // If a value is nil, it is treated as if there is no constraint. type RequiredVersions struct { // When non nil, a semver range (in the format expected by semver.ParseRange). Azd *string `yaml:"azd,omitempty"` Extensions map[string]*string `yaml:"extensions,omitempty"` } // options supported in azure.yaml type PipelineOptions struct { Provider string `yaml:"provider"` Variables []string `yaml:"variables"` Secrets []string `yaml:"secrets"` } // Project lifecycle event arguments type ProjectLifecycleEventArgs struct { Project *ProjectConfig Args map[string]any } // Function definition for project events type ProjectLifecycleEventHandlerFn func(ctx context.Context, args ProjectLifecycleEventArgs) error type ProjectMetadata struct { // Template is a slug that identifies the template and a version. This attribute should be // in every template that we ship. // ex: todo-python-mongo@version Template string } // HooksConfig is an alias for map of hook names to slice of hook configurations // This custom alias type is used to help support YAML unmarshalling of legacy single hook configurations // and new multiple hook configurations type HooksConfig map[string][]*ext.HookConfig // UnmarshalYAML converts the hooks configuration from YAML supporting both legacy single hook configurations // and new multiple hook configurations func (ch *HooksConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { var legacyConfig map[string]*ext.HookConfig // Attempt to unmarshal the legacy single hook configuration if err := unmarshal(&legacyConfig); err == nil { newConfig := HooksConfig{} for key, value := range legacyConfig { newConfig[key] = []*ext.HookConfig{value} } *ch = newConfig } else { // Unmarshal the new multiple hook configuration var newConfig map[string][]*ext.HookConfig if err := unmarshal(&newConfig); err != nil { return fmt.Errorf("failed to unmarshal hooks configuration: %w", err) } *ch = newConfig } return nil } // MarshalYAML marshals the hooks configuration to YAML supporting both legacy single hook configurations func (ch HooksConfig) MarshalYAML() (interface{}, error) { if len(ch) == 0 { return nil, nil } result := map[string]any{} for key, hooks := range ch { if len(hooks) == 1 { result[key] = hooks[0] } else { result[key] = hooks } } return result, nil }