cli/azd/cmd/up.go (153 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. package cmd import ( "context" "errors" "fmt" "time" "github.com/MakeNowJust/heredoc/v2" "github.com/azure/azure-dev/cli/azd/cmd/actions" "github.com/azure/azure-dev/cli/azd/internal" "github.com/azure/azure-dev/cli/azd/internal/cmd" "github.com/azure/azure-dev/cli/azd/pkg/auth" "github.com/azure/azure-dev/cli/azd/pkg/environment" "github.com/azure/azure-dev/cli/azd/pkg/infra/provisioning" "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/output" "github.com/azure/azure-dev/cli/azd/pkg/output/ux" "github.com/azure/azure-dev/cli/azd/pkg/project" "github.com/azure/azure-dev/cli/azd/pkg/prompt" "github.com/azure/azure-dev/cli/azd/pkg/workflow" "github.com/spf13/cobra" "github.com/spf13/pflag" ) type upFlags struct { cmd.ProvisionFlags cmd.DeployFlags global *internal.GlobalCommandOptions internal.EnvFlag } func (u *upFlags) Bind(local *pflag.FlagSet, global *internal.GlobalCommandOptions) { u.EnvFlag.Bind(local, global) u.global = global u.ProvisionFlags.BindNonCommon(local, global) u.ProvisionFlags.SetCommon(&u.EnvFlag) u.DeployFlags.BindNonCommon(local, global) u.DeployFlags.SetCommon(&u.EnvFlag) } func newUpFlags(cmd *cobra.Command, global *internal.GlobalCommandOptions) *upFlags { flags := &upFlags{} flags.Bind(cmd.Flags(), global) return flags } func newUpCmd() *cobra.Command { return &cobra.Command{ Use: "up", Short: "Provision Azure resources, and deploy your project with a single command.", } } type upAction struct { flags *upFlags console input.Console env *environment.Environment projectConfig *project.ProjectConfig provisioningManager *provisioning.Manager envManager environment.Manager prompters prompt.Prompter importManager *project.ImportManager workflowRunner *workflow.Runner } var defaultUpWorkflow = &workflow.Workflow{ Name: "up", Steps: []*workflow.Step{ {AzdCommand: workflow.Command{Args: []string{"package", "--all"}}}, {AzdCommand: workflow.Command{Args: []string{"provision"}}}, {AzdCommand: workflow.Command{Args: []string{"deploy", "--all"}}}, }, } func newUpAction( flags *upFlags, console input.Console, env *environment.Environment, _ auth.LoggedInGuard, projectConfig *project.ProjectConfig, provisioningManager *provisioning.Manager, envManager environment.Manager, prompters prompt.Prompter, importManager *project.ImportManager, workflowRunner *workflow.Runner, ) actions.Action { return &upAction{ flags: flags, console: console, env: env, projectConfig: projectConfig, provisioningManager: provisioningManager, envManager: envManager, prompters: prompters, importManager: importManager, workflowRunner: workflowRunner, } } func (u *upAction) Run(ctx context.Context) (*actions.ActionResult, error) { infra, err := u.importManager.ProjectInfrastructure(ctx, u.projectConfig) if err != nil { return nil, err } defer func() { _ = infra.Cleanup() }() // TODO(weilim): remove this once we have decided if it's okay to not set AZURE_SUBSCRIPTION_ID and AZURE_LOCATION // early in the up workflow in #3745 err = u.provisioningManager.Initialize(ctx, u.projectConfig.Path, infra.Options) if errors.Is(err, bicep.ErrEnsureEnvPreReqBicepCompileFailed) { // If bicep is not available, we continue to prompt for subscription and location unfiltered err = provisioning.EnsureSubscriptionAndLocation( ctx, u.envManager, u.env, u.prompters, provisioning.EnsureSubscriptionAndLocationOptions{}) if err != nil { return nil, err } } else if err != nil { return nil, err } startTime := time.Now() upWorkflow, has := u.projectConfig.Workflows["up"] if !has { upWorkflow = defaultUpWorkflow } else { u.console.Message(ctx, output.WithGrayFormat("Note: Running custom 'up' workflow from azure.yaml")) } if u.flags.EnvironmentName != "" { ctx = context.WithValue(ctx, envFlagCtxKey, u.flags.EnvFlag) } if err := u.workflowRunner.Run(ctx, upWorkflow); err != nil { return nil, err } return &actions.ActionResult{ Message: &actions.ResultMessage{ Header: fmt.Sprintf("Your up workflow to provision and deploy to Azure completed in %s.", ux.DurationAsText(since(startTime))), }, }, nil } func getCmdUpHelpDescription(c *cobra.Command) string { return generateCmdHelpDescription( heredoc.Docf( `Runs a workflow to %s, %s and %s your application in a single step. The %s workflow can be customized by adding a %s section to your %s. For example, modify the workflow to provision before packaging and deploying: ------------------------- %s workflows: up: - azd: provision - azd: package --all - azd: deploy --all ------------------------- Any azd command and flags are supported in the workflow steps.`, output.WithHighLightFormat("package"), output.WithHighLightFormat("provision"), output.WithHighLightFormat("deploy"), output.WithHighLightFormat("up"), output.WithHighLightFormat("workflows"), output.WithHighLightFormat("azure.yaml"), output.WithGrayFormat("# azure.yaml"), ), nil, ) }