func()

in cli/azd/cmd/init.go [157:379]


func (i *initAction) Run(ctx context.Context) (*actions.ActionResult, error) {
	wd, err := os.Getwd()
	if err != nil {
		return nil, fmt.Errorf("getting cwd: %w", err)
	}

	azdCtx := azdcontext.NewAzdContextWithDirectory(wd)
	i.lazyAzdCtx.SetValue(azdCtx)

	if i.flags.templateBranch != "" && i.flags.templatePath == "" {
		return nil,
			errors.New(
				"using branch argument (-b or --branch) requires a template argument (--template or -t) to be specified")
	}

	// ensure that git is available
	if err := tools.EnsureInstalled(ctx, []tools.ExternalTool{i.gitCli}...); err != nil {
		return nil, err
	}

	// Command title
	i.console.MessageUxItem(ctx, &ux.MessageTitle{
		Title: "Initializing an app to run on Azure (azd init)",
	})

	// AZD supports having .env at the root of the project directory as the initial environment file.
	// godotenv.Load() -> add all the values from the .env file in the process environment
	// If AZURE_ENV_NAME is set in the .env file, it will be used to name the environment during env initialize.
	if err := godotenv.Overload(); err != nil {
		// ignore the error if the file does not exist
		if !os.IsNotExist(err) {
			return nil, fmt.Errorf("reading .env file: %w", err)
		}
	}
	if i.flags.EnvFlag.EnvironmentName == "" ||
		(i.flags.EnvFlag.EnvironmentName != "" && !i.flags.EnvFlag.FromArg()) {
		// only azd init supports using .env to influence the command. The `-e` flag is linked to the
		// env var AZURE_ENV_NAME, which means it could've be set either from ENV or from arg.
		// re-setting the value here after loading the .env file overrides any value coming from the system env but
		// doest not override the value coming from the arg.
		i.flags.EnvFlag.EnvironmentName = os.Getenv(environment.EnvNameEnvVarName)
	}

	var existingProject bool
	if _, err := os.Stat(azdCtx.ProjectPath()); err == nil {
		existingProject = true
	} else if errors.Is(err, os.ErrNotExist) {
		existingProject = false
	} else {
		return nil, fmt.Errorf("checking if project exists: %w", err)
	}

	var initTypeSelect initType
	if i.flags.templatePath != "" || len(i.flags.templateTags) > 0 {
		// an explicit --template passed, always initialize from app template
		initTypeSelect = initAppTemplate
	}

	if i.flags.fromCode {
		if i.flags.templatePath != "" {
			return nil, errors.New("only one of init modes: --template, or --from-code should be set")
		}
		initTypeSelect = initFromApp
	}

	if i.flags.templatePath == "" && !i.flags.fromCode && existingProject {
		// only initialize environment when no mode is set explicitly
		initTypeSelect = initEnvironment
	}

	if initTypeSelect == initUnknown {
		initTypeSelect, err = promptInitType(i.console, ctx)
		if err != nil {
			return nil, err
		}
	}

	header := "New project initialized!"
	followUp := heredoc.Docf(`
	You can view the template code in your directory: %s
	Learn more about running 3rd party code on our DevHub: %s`,
		output.WithLinkFormat("%s", wd),
		output.WithLinkFormat("%s", "https://aka.ms/azd-third-party-code-notice"))

	switch initTypeSelect {
	case initAppTemplate:
		tracing.SetUsageAttributes(fields.InitMethod.String("template"))
		template, err := i.initializeTemplate(ctx, azdCtx)
		if err != nil {
			return nil, err
		}

		if _, err := i.initializeEnv(ctx, azdCtx, template.Metadata); err != nil {
			return nil, err
		}

		if i.flags.up {
			// Prompt to deploy to Azure
			deploy, err := i.console.Confirm(ctx, input.ConsoleOptions{
				Message:      "Do you want to run " + output.WithHighLightFormat("azd up") + " now?",
				DefaultValue: true,
				Help: "Template files have been initialized in your local directory. " +
					"If you want to provision and deploy now without making changes, select Y. If not, select N.",
			})
			if err != nil {
				return nil, err
			}

			if deploy {
				// Call azd up
				startTime := time.Now()
				i.azd.SetArgs([]string{"up", "--cwd", azdCtx.ProjectDirectory()})
				err := i.azd.ExecuteContext(ctx)
				header = "New project initialized! Provision and deploy to Azure was completed in " +
					ux.DurationAsText(since(startTime)) + "."
				if err != nil {
					return nil, err
				}
			}
		}

	case initFromApp:
		tracing.SetUsageAttributes(fields.InitMethod.String("app"))

		header = "Your app is ready for the cloud!"
		followUp = "You can provision and deploy your app to Azure by running the " + output.WithHighLightFormat("azd up") +
			" command in this directory. For more information on configuring your app, see " +
			output.WithHighLightFormat("./next-steps.md")
		entries, err := os.ReadDir(azdCtx.ProjectDirectory())
		if err != nil {
			return nil, fmt.Errorf("reading current directory: %w", err)
		}

		if len(entries) == 0 {
			return nil, &internal.ErrorWithSuggestion{
				Err: errors.New("no files found in the current directory"),
				Suggestion: "Ensure you're in the directory where your app code is located and try again." +
					" If you do not have code and would like to start with an app template, run '" +
					output.WithHighLightFormat("azd init") + "' and select the option to " +
					color.MagentaString("Use a template") + ".",
			}
		}

		err = i.repoInitializer.InitFromApp(ctx, azdCtx, func() (*environment.Environment, error) {
			return i.initializeEnv(ctx, azdCtx, templates.Metadata{})
		})
		if err != nil {
			return nil, err
		}
	case initEnvironment:
		env, err := i.initializeEnv(ctx, azdCtx, templates.Metadata{})
		if err != nil {
			return nil, err
		}

		header = fmt.Sprintf("Initialized environment %s.", env.Name())
		followUp = ""
	case initProject:
		tracing.SetUsageAttributes(fields.InitMethod.String("project"))

		composeAlphaEnabled := i.featuresManager.IsEnabled(composeFeature)
		if !composeAlphaEnabled {
			err = i.repoInitializer.InitializeMinimal(ctx, azdCtx)
			if err != nil {
				return nil, err
			}

			_, err := i.initializeEnv(ctx, azdCtx, templates.Metadata{})
			if err != nil {
				return nil, err
			}

			followUp = ""
		} else {
			fi, err := os.Stat(azdCtx.ProjectPath())
			if err != nil && !errors.Is(err, os.ErrNotExist) {
				return nil, err
			}

			if fi != nil {
				return nil, fmt.Errorf("project already initialized")
			}

			name, err := i.console.Prompt(ctx, input.ConsoleOptions{
				Message:      "What is the name of your project?",
				DefaultValue: azdcontext.ProjectName(azdCtx.ProjectDirectory()),
			})
			if err != nil {
				return nil, err
			}

			prjConfig := project.ProjectConfig{
				Name: name,
			}

			if composeAlphaEnabled {
				prjConfig.MetaSchemaVersion = "alpha"
			}

			err = project.Save(ctx, &prjConfig, azdCtx.ProjectPath())
			if err != nil {
				return nil, fmt.Errorf("saving project config: %w", err)
			}

			followUp = "Run " + output.WithHighLightFormat("azd add") + " to add new Azure components to your project."
		}

		header = "Generated azure.yaml project file."
	default:
		panic("unhandled init type")
	}

	if err := i.initializeExtensions(ctx, azdCtx); err != nil {
		return nil, fmt.Errorf("initializing project extensions: %w", err)
	}

	return &actions.ActionResult{
		Message: &actions.ResultMessage{
			Header:   header,
			FollowUp: followUp,
		},
	}, nil
}