Skip to content

Initial support for environment types with azd env new --type <type> #5412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions cli/azd/cmd/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,19 @@ func registerCommonDependencies(container *ioc.NestedContainer) {
// semantics to follow.
envValue, err := cmd.Flags().GetString(internal.EnvironmentNameFlagName)
if err != nil {
log.Printf("'%s'command asked for envFlag, but envFlag was not included in cmd.Flags().", cmd.CommandPath())
log.Printf("'%s' command asked for envFlag, but envFlag was not included in cmd.Flags().", cmd.CommandPath())
envValue = ""
}

envTypeValue, err := cmd.Flags().GetString(internal.EnvironmentTypeFlagName)
if err != nil {
log.Printf(
"'%s' command asked for envTypeFlag, but envTypeFlag was not included in cmd.Flags().",
cmd.CommandPath(),
)
envTypeValue = ""
}

if envValue == "" {
// If no explicit environment flag was set, but one was provided
// in the context, use that instead.
Expand All @@ -190,7 +199,10 @@ func registerCommonDependencies(container *ioc.NestedContainer) {
}
}

return internal.EnvFlag{EnvironmentName: envValue}
return internal.EnvFlag{
EnvironmentName: envValue,
EnvironmentType: envTypeValue,
}
})

container.MustRegisterSingleton(func(cmd *cobra.Command) CmdAnnotations {
Expand Down Expand Up @@ -229,9 +241,10 @@ func registerCommonDependencies(container *ioc.NestedContainer) {
}

environmentName := envFlags.EnvironmentName
environmentType := envFlags.EnvironmentType
var err error

env, err := envManager.LoadOrInitInteractive(ctx, environmentName)
env, err := envManager.LoadOrInitInteractiveWithType(ctx, environmentName, environmentType)
if err != nil {
return nil, fmt.Errorf("loading environment: %w", err)
}
Expand Down Expand Up @@ -382,14 +395,23 @@ func registerCommonDependencies(container *ioc.NestedContainer) {
func(
ctx context.Context,
lazyAzdContext *lazy.Lazy[*azdcontext.AzdContext],
envFlags internal.EnvFlag,
) *lazy.Lazy[*project.ProjectConfig] {
return lazy.NewLazy(func() (*project.ProjectConfig, error) {
azdCtx, err := lazyAzdContext.GetValue()
if err != nil {
return nil, err
}

projectConfig, err := project.Load(ctx, azdCtx.ProjectPath())
// Use environment-specific project path when an environment is specified
var projectPath string
if envFlags.EnvironmentName != "" {
projectPath = azdCtx.ProjectPathForEnvironment(envFlags.EnvironmentName)
} else {
projectPath = azdCtx.ProjectPath()
}

projectConfig, err := project.Load(ctx, projectPath)
if err != nil {
return nil, err
}
Expand All @@ -405,6 +427,7 @@ func registerCommonDependencies(container *ioc.NestedContainer) {
lazyProjectConfig *lazy.Lazy[*project.ProjectConfig],
lazyAzdContext *lazy.Lazy[*azdcontext.AzdContext],
lazyLocalEnvStore *lazy.Lazy[environment.LocalDataStore],
envFlags internal.EnvFlag,
) (*cloud.Cloud, error) {

// Precedence for cloud configuration:
Expand All @@ -424,8 +447,15 @@ func registerCommonDependencies(container *ioc.NestedContainer) {
localEnvStore, _ := lazyLocalEnvStore.GetValue()
if azdCtx, err := lazyAzdContext.GetValue(); err == nil {
if azdCtx != nil && localEnvStore != nil {
if defaultEnvName, err := azdCtx.GetDefaultEnvironmentName(); err == nil {
if env, err := localEnvStore.Get(ctx, defaultEnvName); err == nil {
var envName string
if envFlags.EnvironmentName != "" {
envName = envFlags.EnvironmentName
} else if defaultEnvName, err := azdCtx.GetDefaultEnvironmentName(); err == nil {
envName = defaultEnvName
}

if envName != "" {
if env, err := localEnvStore.Get(ctx, envName); err == nil {
if cloudConfigurationNode, exists := env.Config.Get(cloud.ConfigPath); exists {
if value, err := cloud.ParseCloudConfig(cloudConfigurationNode); err == nil {
cloudConfig, err := cloud.NewCloud(value)
Expand All @@ -438,7 +468,7 @@ func registerCommonDependencies(container *ioc.NestedContainer) {
Suggestion: fmt.Sprintf(
"Set the cloud configuration by editing the 'cloud' node in the config.json "+
"file for the %s environment\n%s",
defaultEnvName,
envName,
validClouds,
),
}
Expand Down
15 changes: 15 additions & 0 deletions cli/azd/cmd/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/azure/azure-dev/cli/azd/pkg/ioc"
"github.com/azure/azure-dev/cli/azd/pkg/lazy"
"github.com/azure/azure-dev/cli/azd/pkg/project"
"github.com/spf13/cobra"
"github.com/stretchr/testify/require"
)

Expand All @@ -19,6 +20,13 @@ func Test_Lazy_Project_Config_Resolution(t *testing.T) {
container := ioc.NewNestedContainer(nil)
ioc.RegisterInstance(container, ctx)

// Register a mock cobra command for testing
mockCmd := &cobra.Command{}
mockCmd.SetContext(ctx)
// Add the environment flag to avoid the "envFlag was not included in cmd.Flags()" error
mockCmd.Flags().StringP("environment", "e", "", "Environment name")
ioc.RegisterInstance(container, mockCmd)

registerCommonDependencies(container)

// Register the testing lazy component
Expand Down Expand Up @@ -88,6 +96,13 @@ func Test_Lazy_AzdContext_Resolution(t *testing.T) {
container := ioc.NewNestedContainer(nil)
ioc.RegisterInstance(container, ctx)

// Register a mock cobra command for testing
mockCmd := &cobra.Command{}
mockCmd.SetContext(ctx)
// Add the environment flag to avoid the "envFlag was not included in cmd.Flags()" error
mockCmd.Flags().StringP("environment", "e", "", "Environment name")
ioc.RegisterInstance(container, mockCmd)

registerCommonDependencies(container)

// Register the testing lazy component
Expand Down
56 changes: 56 additions & 0 deletions cli/azd/cmd/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"io"
"os"
"path/filepath"
"slices"
"strings"
"time"
Expand All @@ -27,6 +28,7 @@ import (
"github.com/azure/azure-dev/cli/azd/pkg/infra/provisioning/bicep"
"github.com/azure/azure-dev/cli/azd/pkg/input"
"github.com/azure/azure-dev/cli/azd/pkg/keyvault"
"github.com/azure/azure-dev/cli/azd/pkg/osutil"
"github.com/azure/azure-dev/cli/azd/pkg/output"
"github.com/azure/azure-dev/cli/azd/pkg/output/ux"
"github.com/azure/azure-dev/cli/azd/pkg/project"
Expand Down Expand Up @@ -808,6 +810,7 @@ func (e *envListAction) Run(ctx context.Context) (*actions.ActionResult, error)
type envNewFlags struct {
subscription string
location string
envType string
global *internal.GlobalCommandOptions
}

Expand All @@ -819,6 +822,7 @@ func (f *envNewFlags) Bind(local *pflag.FlagSet, global *internal.GlobalCommandO
"Name or ID of an Azure subscription to use for the new environment",
)
local.StringVarP(&f.location, "location", "l", "", "Azure location for the new environment")
local.StringVarP(&f.envType, "type", "t", "", "The type of the environment (e.g., dev, test, prod). (Experimental)")

f.global = global
}
Expand Down Expand Up @@ -870,17 +874,69 @@ func (en *envNewAction) Run(ctx context.Context) (*actions.ActionResult, error)
environmentName = en.args[0]
}

envType := en.flags.envType
envSpec := environment.Spec{
Name: environmentName,
Subscription: en.flags.subscription,
Location: en.flags.location,
Type: envType,
}

env, err := en.envManager.Create(ctx, envSpec)
if err != nil {
return nil, fmt.Errorf("creating new environment: %w", err)
}

// Create environment-specific project file if environment type is specified
if envType != "" {
envProjectFileName := azdcontext.ProjectFileNameForEnvironmentType(envType)
envProjectPath := filepath.Join(en.azdCtx.ProjectDirectory(), envProjectFileName)

if _, err := os.Stat(envProjectPath); os.IsNotExist(err) {
// Check for current project file to copy from
currentProjectFileName := en.azdCtx.ProjectFileName()
currentProjectPath := en.azdCtx.ProjectPath()
shouldCopy := false

if _, err := os.Stat(currentProjectPath); err == nil {
// Prompt user if they want to copy content from azure.yaml
shouldCopy, err = en.console.Confirm(ctx, input.ConsoleOptions{
Message: fmt.Sprintf("Copy contents of %s to %s?", currentProjectFileName, envProjectFileName),
DefaultValue: true,
})
if err != nil {
return nil, fmt.Errorf("prompting to copy azure.yaml content: %w", err)
}
} else if !os.IsNotExist(err) {
return nil, fmt.Errorf("checking for %s: %w", currentProjectFileName, err)
}

if shouldCopy {
content, err := os.ReadFile(currentProjectPath)
if err != nil {
return nil, fmt.Errorf("reading main project file: %w", err)
}

if err := os.WriteFile(envProjectPath, content, osutil.PermissionFile); err != nil {
return nil, fmt.Errorf("creating environment project file: %w", err)
}

en.console.MessageUxItem(ctx, &ux.DoneMessage{
Message: fmt.Sprintf("Created %s", envProjectFileName),
})
} else {
_, err = project.New(ctx, envProjectPath, azdcontext.ProjectName(en.azdCtx.ProjectDirectory()))
if err != nil {
return nil, fmt.Errorf("creating empty project file: %w", err)
}

en.console.MessageUxItem(ctx, &ux.DoneMessage{
Message: fmt.Sprintf("Created empty %s", envProjectFileName),
})
}
}
}

envs, err := en.envManager.List(ctx)
if err != nil {
return nil, fmt.Errorf("listing environments: %w", err)
Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-deploy.snap
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Usage

Flags
--all : Deploys all services that are listed in azure.yaml
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.
--from-package string : Deploys the packaged service located at the provided path. Supports zipped file packages (file path) or container images (image tag).

Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-down.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Usage
azd down [flags]

Flags
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.
--force : Does not require confirmation before it deletes resources.
--purge : Does not require confirmation before it permanently deletes resources that are soft-deleted by default (for example, key vaults).
Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-env-get-value.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Usage
azd env get-value <keyName> [flags]

Flags
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.

Global Flags
Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-env-get-values.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Usage
azd env get-values [flags]

Flags
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.

Global Flags
Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-env-new.snap
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Usage
Flags
-l, --location string : Azure location for the new environment
--subscription string : Name or ID of an Azure subscription to use for the new environment
-t, --type string : The type of the environment (e.g., dev, test, prod). (Experimental)

Global Flags
-C, --cwd string : Sets the current working directory.
Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-env-refresh.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Usage
azd env refresh <environment> [flags]

Flags
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.
--hint string : Hint to help identify the environment to refresh

Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-env-set-secret.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Usage
azd env set-secret <name> [flags]

Flags
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.

Global Flags
Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-env-set.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Usage
azd env set [<key> <value>] | [<key>=<value> ...] | [--file <filepath>] [flags]

Flags
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.
--file string : Path to .env formatted file to load environment values from.

Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-hooks-run.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Usage
azd hooks run <name> [flags]

Flags
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.
--platform string : Forces hooks to run for the specified platform.
--service string : Only runs hooks for the specified service.
Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-infra-generate.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Usage
azd infra generate [flags]

Flags
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.
--force : Overwrite any existing files without prompting

Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-init.snap
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Usage

Flags
-b, --branch string : The template branch to initialize from. Must be used with a template argument (--template or -t).
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.
-f, --filter strings : The tag(s) used to filter template results. Supports comma-separated values.
--from-code : Initializes a new application from your existing code.
Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-monitor.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Usage
azd monitor [flags]

Flags
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.
--live : Open a browser to Application Insights Live Metrics. Live Metrics is currently not supported for Python apps.
--logs : Open a browser to Application Insights Logs.
Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-package.snap
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Usage

Flags
--all : Packages all services that are listed in azure.yaml
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.
--output-path string : File or folder path where the generated packages will be saved.

Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-pipeline-config.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Usage
Flags
-m, --applicationServiceManagementReference string : Service Management Reference. References application or service contact information from a Service or Asset Management database. This value must be a Universally Unique Identifier (UUID). You can set this value globally by running azd config set pipeline.config.applicationServiceManagementReference <UUID>.
--auth-type string : The authentication type used between the pipeline provider and Azure for deployment (Only valid for GitHub provider). Valid values: federated, client-credentials.
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.
--principal-id string : The client id of the service principal to use to grant access to Azure resources as part of the pipeline.
--principal-name string : The name of the service principal to use to grant access to Azure resources as part of the pipeline.
Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-provision.snap
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Usage
azd provision [flags]

Flags
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.
--no-state : (Bicep only) Forces a fresh deployment based on current Bicep template files, ignoring any stored deployment state.
--preview : Preview changes to Azure resources.
Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-restore.snap
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Usage

Flags
--all : Restores all services that are listed in azure.yaml
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.

Global Flags
Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-show.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Usage
azd show [resource name or ID] [flags]

Flags
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.
--show-secrets : Unmask secrets in output.

Expand Down
1 change: 1 addition & 0 deletions cli/azd/cmd/testdata/TestUsage-azd-up.snap
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Usage
azd up [flags]

Flags
--env-type string : The type of the environment (e.g., dev, test, prod). (Experimental)
-e, --environment string : The name of the environment to use.

Global Flags
Expand Down
Loading
Loading