func NewRootCmd()

in cli/azd/cmd/root.go [38:428]


func NewRootCmd(
	staticHelp bool,
	middlewareChain []*actions.MiddlewareRegistration,
	rootContainer *ioc.NestedContainer,
) *cobra.Command {
	prevDir := ""
	opts := &internal.GlobalCommandOptions{GenerateStaticHelp: staticHelp}
	opts.EnableTelemetry = telemetry.IsTelemetryEnabled()

	productName := "The Azure Developer CLI"
	if opts.GenerateStaticHelp {
		productName = "The Azure Developer CLI (`azd`)"
	}

	rootCmd := &cobra.Command{
		Use:   "azd",
		Short: fmt.Sprintf("%s is an open-source tool that helps onboard and manage your application on Azure", productName),
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			// If there was a platform configuration error report it to the user until it is resolved
			// Using fmt.Printf directly here since we can't leverage our IoC container to resolve a console instance
			if errors.Is(platform.Error, platform.ErrPlatformNotSupported) {
				fmt.Print(output.WithWarningFormat("WARNING: %s\n\n", platform.Error.Error()))
			}

			if opts.Cwd != "" {
				current, err := os.Getwd()

				if err != nil {
					return err
				}

				prevDir = current

				if err := os.Chdir(opts.Cwd); err != nil {
					return fmt.Errorf("failed to change directory to %s: %w", opts.Cwd, err)
				}
			}

			return nil
		},
		PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
			// This is just for cleanliness and making writing tests simpler since
			// we can just remove the entire project folder afterwards.
			// In practical execution, this wouldn't affect much, since the CLI is exiting.
			if prevDir != "" {
				return os.Chdir(prevDir)
			}

			return nil
		},
		SilenceUsage:      true,
		DisableAutoGenTag: true,
	}

	rootCmd.CompletionOptions.HiddenDefaultCmd = true

	root := actions.NewActionDescriptor("azd", &actions.ActionDescriptorOptions{
		Command: rootCmd,
		FlagsResolver: func(cmd *cobra.Command) *internal.GlobalCommandOptions {
			rootCmd.PersistentFlags().StringVarP(&opts.Cwd, "cwd", "C", "", "Sets the current working directory.")
			rootCmd.PersistentFlags().
				BoolVar(&opts.EnableDebugLogging, "debug", false, "Enables debugging and diagnostics logging.")
			rootCmd.PersistentFlags().
				BoolVar(
					&opts.NoPrompt,
					"no-prompt",
					false,
					"Accepts the default value instead of prompting, or it fails if there is no default.")

			// The telemetry system is responsible for reading these flags value and using it to configure the telemetry
			// system, but we still need to add it to our flag set so that when we parse the command line with Cobra we
			// don't error due to an "unknown flag".
			var traceLogFile string
			var traceLogEndpoint string

			rootCmd.PersistentFlags().StringVar(&traceLogFile, "trace-log-file", "", "Write a diagnostics trace to a file.")
			_ = rootCmd.PersistentFlags().MarkHidden("trace-log-file")

			rootCmd.PersistentFlags().StringVar(
				&traceLogEndpoint, "trace-log-url", "", "Send traces to an Open Telemetry compatible endpoint.")
			_ = rootCmd.PersistentFlags().MarkHidden("trace-log-url")

			return opts
		},
	})

	configActions(root, opts)
	envActions(root)
	infraActions(root)
	pipelineActions(root)
	telemetryActions(root)
	templatesActions(root)
	authActions(root)
	hooksActions(root)

	root.Add("version", &actions.ActionDescriptorOptions{
		Command: &cobra.Command{
			Short: "Print the version number of Azure Developer CLI.",
		},
		ActionResolver:   newVersionAction,
		FlagsResolver:    newVersionFlags,
		DisableTelemetry: true,
		OutputFormats:    []output.Format{output.JsonFormat, output.NoneFormat},
		DefaultFormat:    output.NoneFormat,
		GroupingOptions: actions.CommandGroupOptions{
			RootLevelHelp: actions.CmdGroupAbout,
		},
	})

	root.Add("vs-server", &actions.ActionDescriptorOptions{
		Command:        newVsServerCmd(),
		FlagsResolver:  newVsServerFlags,
		ActionResolver: newVsServerAction,
		OutputFormats:  []output.Format{output.NoneFormat},
		DefaultFormat:  output.NoneFormat,
	})

	root.Add("show", &actions.ActionDescriptorOptions{
		Command:        show.NewShowCmd(),
		FlagsResolver:  show.NewShowFlags,
		ActionResolver: show.NewShowAction,
		OutputFormats:  []output.Format{output.JsonFormat, output.NoneFormat},
		DefaultFormat:  output.NoneFormat,
		GroupingOptions: actions.CommandGroupOptions{
			RootLevelHelp: actions.CmdGroupMonitor,
		},
	})

	//deprecate:cmd hide login
	login := newLoginCmd("")
	login.Hidden = true
	root.Add("login", &actions.ActionDescriptorOptions{
		Command:        login,
		FlagsResolver:  newLoginFlags,
		ActionResolver: newLoginAction,
		OutputFormats:  []output.Format{output.JsonFormat, output.NoneFormat},
		DefaultFormat:  output.NoneFormat,
	})

	//deprecate:cmd hide logout
	logout := newLogoutCmd("")
	logout.Hidden = true
	root.Add("logout", &actions.ActionDescriptorOptions{
		Command:        logout,
		ActionResolver: newLogoutAction,
	})

	root.Add("init", &actions.ActionDescriptorOptions{
		Command:        newInitCmd(),
		FlagsResolver:  newInitFlags,
		ActionResolver: newInitAction,
		HelpOptions: actions.ActionHelpOptions{
			Description: getCmdInitHelpDescription,
			Footer:      getCmdInitHelpFooter,
		},
		GroupingOptions: actions.CommandGroupOptions{
			RootLevelHelp: actions.CmdGroupConfig,
		},
	})

	root.
		Add("restore", &actions.ActionDescriptorOptions{
			Command:        newRestoreCmd(),
			FlagsResolver:  newRestoreFlags,
			ActionResolver: newRestoreAction,
			OutputFormats:  []output.Format{output.JsonFormat, output.NoneFormat},
			DefaultFormat:  output.NoneFormat,
			HelpOptions: actions.ActionHelpOptions{
				Description: getCmdRestoreHelpDescription,
				Footer:      getCmdRestoreHelpFooter,
			},
			GroupingOptions: actions.CommandGroupOptions{
				RootLevelHelp: actions.CmdGroupConfig,
			},
		}).
		UseMiddleware("hooks", middleware.NewHooksMiddleware).
		UseMiddleware("extensions", middleware.NewExtensionsMiddleware)

	root.
		Add("build", &actions.ActionDescriptorOptions{
			Command:        newBuildCmd(),
			FlagsResolver:  newBuildFlags,
			ActionResolver: newBuildAction,
			OutputFormats:  []output.Format{output.JsonFormat, output.NoneFormat},
			DefaultFormat:  output.NoneFormat,
		}).
		UseMiddleware("hooks", middleware.NewHooksMiddleware).
		UseMiddleware("extensions", middleware.NewExtensionsMiddleware)

	root.
		Add("provision", &actions.ActionDescriptorOptions{
			Command:        cmd.NewProvisionCmd(),
			FlagsResolver:  cmd.NewProvisionFlags,
			ActionResolver: cmd.NewProvisionAction,
			OutputFormats:  []output.Format{output.JsonFormat, output.NoneFormat},
			DefaultFormat:  output.NoneFormat,
			HelpOptions: actions.ActionHelpOptions{
				Description: cmd.GetCmdProvisionHelpDescription,
				Footer:      getCmdHelpDefaultFooter,
			},
			GroupingOptions: actions.CommandGroupOptions{
				RootLevelHelp: actions.CmdGroupManage,
			},
		}).
		UseMiddlewareWhen("hooks", middleware.NewHooksMiddleware, func(descriptor *actions.ActionDescriptor) bool {
			if onPreview, _ := descriptor.Options.Command.Flags().GetBool("preview"); onPreview {
				log.Println("Skipping provision hooks due to preview flag.")
				return false
			}
			return true
		}).
		UseMiddlewareWhen("extensions", middleware.NewExtensionsMiddleware, func(descriptor *actions.ActionDescriptor) bool {
			if onPreview, _ := descriptor.Options.Command.Flags().GetBool("preview"); onPreview {
				log.Println("Skipping provision hooks due to preview flag.")
				return false
			}
			return true
		})

	root.
		Add("package", &actions.ActionDescriptorOptions{
			Command:        newPackageCmd(),
			FlagsResolver:  newPackageFlags,
			ActionResolver: newPackageAction,
			OutputFormats:  []output.Format{output.JsonFormat, output.NoneFormat},
			DefaultFormat:  output.NoneFormat,
			HelpOptions: actions.ActionHelpOptions{
				Description: getCmdPackageHelpDescription,
				Footer:      getCmdPackageHelpFooter,
			},
			GroupingOptions: actions.CommandGroupOptions{
				RootLevelHelp: actions.CmdGroupManage,
			},
		}).
		UseMiddleware("hooks", middleware.NewHooksMiddleware).
		UseMiddleware("extensions", middleware.NewExtensionsMiddleware)

	root.
		Add("deploy", &actions.ActionDescriptorOptions{
			Command:        cmd.NewDeployCmd(),
			FlagsResolver:  cmd.NewDeployFlags,
			ActionResolver: cmd.NewDeployAction,
			OutputFormats:  []output.Format{output.JsonFormat, output.NoneFormat},
			DefaultFormat:  output.NoneFormat,
			HelpOptions: actions.ActionHelpOptions{
				Description: cmd.GetCmdDeployHelpDescription,
				Footer:      cmd.GetCmdDeployHelpFooter,
			},
			GroupingOptions: actions.CommandGroupOptions{
				RootLevelHelp: actions.CmdGroupManage,
			},
		}).
		UseMiddleware("hooks", middleware.NewHooksMiddleware).
		UseMiddleware("extensions", middleware.NewExtensionsMiddleware)

	root.
		Add("up", &actions.ActionDescriptorOptions{
			Command:        newUpCmd(),
			FlagsResolver:  newUpFlags,
			ActionResolver: newUpAction,
			OutputFormats:  []output.Format{output.JsonFormat, output.NoneFormat},
			DefaultFormat:  output.NoneFormat,
			HelpOptions: actions.ActionHelpOptions{
				Description: getCmdUpHelpDescription,
			},
			GroupingOptions: actions.CommandGroupOptions{
				RootLevelHelp: actions.CmdGroupManage,
			},
		}).
		UseMiddleware("hooks", middleware.NewHooksMiddleware).
		UseMiddleware("extensions", middleware.NewExtensionsMiddleware)

	root.Add("monitor", &actions.ActionDescriptorOptions{
		Command:        newMonitorCmd(),
		FlagsResolver:  newMonitorFlags,
		ActionResolver: newMonitorAction,
		HelpOptions: actions.ActionHelpOptions{
			Description: getCmdMonitorHelpDescription,
			Footer:      getCmdMonitorHelpFooter,
		},
		GroupingOptions: actions.CommandGroupOptions{
			RootLevelHelp: actions.CmdGroupMonitor,
		},
	})

	root.
		Add("down", &actions.ActionDescriptorOptions{
			Command:        newDownCmd(),
			FlagsResolver:  newDownFlags,
			ActionResolver: newDownAction,
			OutputFormats:  []output.Format{output.JsonFormat, output.NoneFormat},
			DefaultFormat:  output.NoneFormat,
			HelpOptions: actions.ActionHelpOptions{
				Description: getCmdDownHelpDescription,
				Footer:      getCmdDownHelpFooter,
			},
			GroupingOptions: actions.CommandGroupOptions{
				RootLevelHelp: actions.CmdGroupManage,
			},
		}).
		UseMiddleware("hooks", middleware.NewHooksMiddleware).
		UseMiddleware("extensions", middleware.NewExtensionsMiddleware)
	root.
		Add("add", &actions.ActionDescriptorOptions{
			Command:        add.NewAddCmd(),
			ActionResolver: add.NewAddAction,
		})

	// Register any global middleware defined by the caller
	if len(middlewareChain) > 0 {
		for _, registration := range middlewareChain {
			root.UseMiddlewareWhen(registration.Name, registration.Resolver, registration.Predicate)
		}
	}

	// Global middleware registration
	root.
		UseMiddleware("debug", middleware.NewDebugMiddleware).
		UseMiddleware("ux", middleware.NewUxMiddleware).
		UseMiddlewareWhen("telemetry", middleware.NewTelemetryMiddleware, func(descriptor *actions.ActionDescriptor) bool {
			return !descriptor.Options.DisableTelemetry
		})

	// Register common dependencies for the IoC rootContainer
	if rootContainer == nil {
		rootContainer = ioc.NewNestedContainer(nil)
	}
	ioc.RegisterNamedInstance(rootContainer, "root-cmd", rootCmd)
	registerCommonDependencies(rootContainer)

	// Conditionally register the 'extension' commands if the feature is enabled
	err := rootContainer.Invoke(func(alphaFeatureManager *alpha.FeatureManager, extensionManager *extensions.Manager) error {
		if alphaFeatureManager.IsEnabled(extensions.FeatureExtensions) {
			// Enables the "extension (ext)" command group.
			extensionActions(root)

			// Enables custom extension commands
			installedExtensions, err := extensionManager.ListInstalled()
			if err != nil {
				return fmt.Errorf("Failed to get installed extensions: %w", err)
			}

			// Bind custom extension commands for extensions that expose the capability
			for _, ext := range installedExtensions {
				if ext.HasCapability(extensions.CustomCommandCapability) {
					if err := bindExtension(rootContainer, root, ext); err != nil {
						return fmt.Errorf("Failed to bind extension commands: %w", err)
					}
				}
			}
		}

		return nil
	})

	if err != nil {
		panic(err)
	}

	// Initialize the platform specific components for the IoC container
	// Only container resolution errors will return an error
	// Invalid configurations will fall back to default platform
	if _, err := platform.Initialize(rootContainer, azd.PlatformKindDefault); err != nil {
		panic(err)
	}

	// Compose the hierarchy of action descriptions into cobra commands
	var cobraBuilder *CobraBuilder
	if err := rootContainer.Resolve(&cobraBuilder); err != nil {
		panic(err)
	}

	cmd, err := cobraBuilder.BuildCommand(root)

	if err != nil {
		// If their is a container registration issue or similar we'll get an error at this point
		// Error descriptions should be clear enough to resolve the issue
		panic(err)
	}

	// The help template has to be set after calling `BuildCommand()` to ensure the command tree is built
	cmd.SetHelpTemplate(generateCmdHelp(
		cmd,
		generateCmdHelpOptions{
			Description: getCmdHelpDefaultDescription,
			Commands:    func(c *cobra.Command) string { return getCmdHelpGroupedCommands(getCmdRootHelpCommands(c)) },
			Footer:      getCmdRootHelpFooter,
		}))

	return cmd
}