in cli/azd/extensions/microsoft.azd.extensions/internal/cmd/init.go [133:334]
func runInitAction(ctx context.Context, flags *initFlags) error {
// Create a new context that includes the AZD access token
ctx = azdext.WithAccessToken(ctx)
// Create a new AZD client
azdClient, err := azdext.NewAzdClient()
if err != nil {
return fmt.Errorf("failed to create azd client: %w", err)
}
defer azdClient.Close()
var extensionMetadata *models.ExtensionSchema
if flags.noPrompt {
// In headless mode, use the provided command-line arguments
extensionMetadata, err = collectExtensionMetadataFromFlags(flags)
if err != nil {
return err
}
} else if !flags.createRegistry {
// Interactive mode - collect metadata through prompts
extensionMetadata, err = collectExtensionMetadata(ctx, azdClient)
if err != nil {
return fmt.Errorf("failed to collect extension metadata: %w", err)
}
fmt.Println()
confirmResponse, err := azdClient.
Prompt().
Confirm(ctx, &azdext.ConfirmRequest{
Options: &azdext.ConfirmOptions{
Message: fmt.Sprintf("Continue creating the extension at %s?", extensionMetadata.Id),
DefaultValue: internal.ToPtr(false),
Placeholder: "no",
HelpMessage: "Confirm if you want to continue creating the extension.",
},
})
if err != nil {
return fmt.Errorf("failed to confirm extension, %w", err)
}
if !*confirmResponse.Value {
return errors.New("extension creation cancelled by user")
}
}
localRegistryExists := false
createLocalExtensionSourceAction := func(spf ux.SetProgressFunc) (ux.TaskState, error) {
if has, err := hasLocalRegistry(); err == nil && has {
localRegistryExists = true
return ux.Skipped, nil
}
if err := createLocalRegistry(); err != nil {
return ux.Error, common.NewDetailedError(
"Registry creation failed",
fmt.Errorf("failed to create local registry: %w", err),
)
}
return ux.Success, nil
}
createExtensionDirectoryAction := func(spf ux.SetProgressFunc) (ux.TaskState, error) {
if err := createExtensionDirectory(ctx, azdClient, extensionMetadata); err != nil {
return ux.Error, common.NewDetailedError(
"Error creating directory",
fmt.Errorf("failed to create extension directory: %w", err),
)
}
return ux.Success, nil
}
buildExtensionAction := func(spf ux.SetProgressFunc) (ux.TaskState, error) {
cmd := exec.Command("azd", "x", "build", "--skip-install")
cmd.Dir = extensionMetadata.Path
if err := cmd.Run(); err != nil {
return ux.Error, common.NewDetailedError(
"Build failed",
fmt.Errorf("failed to build extension: %w", err),
)
}
return ux.Success, nil
}
packageExtensionAction := func(spf ux.SetProgressFunc) (ux.TaskState, error) {
cmd := exec.Command("azd", "x", "pack")
cmd.Dir = extensionMetadata.Path
if err := cmd.Run(); err != nil {
return ux.Error, common.NewDetailedError(
"Package failed",
fmt.Errorf("failed to package extension: %w", err),
)
}
return ux.Success, nil
}
publishExtensionAction := func(spf ux.SetProgressFunc) (ux.TaskState, error) {
cmd := exec.Command("azd", "x", "publish")
cmd.Dir = extensionMetadata.Path
if err := cmd.Run(); err != nil {
return ux.Error, common.NewDetailedError(
"Publish failed",
fmt.Errorf("failed to package extension: %w", err),
)
}
return ux.Success, nil
}
installExtensionAction := func(spf ux.SetProgressFunc) (ux.TaskState, error) {
/* #nosec G204 - Subprocess launched with a potential tainted input or cmd arguments */
cmd := exec.Command("azd", "ext", "install", extensionMetadata.Id, "--source", "local")
cmd.Dir = extensionMetadata.Path
if err := cmd.Run(); err != nil {
return ux.Error, common.NewDetailedError(
"Install failed",
fmt.Errorf("failed to install extension: %w", err),
)
}
return ux.Success, nil
}
taskList := ux.NewTaskList(nil)
if flags.createRegistry {
taskList.AddTask(ux.TaskOptions{
Title: "Create local azd extension source",
Action: createLocalExtensionSourceAction,
})
} else {
taskList.
AddTask(ux.TaskOptions{
Title: "Create local azd extension source",
Action: createLocalExtensionSourceAction,
}).
AddTask(ux.TaskOptions{
Title: fmt.Sprintf("Creating extension directory %s", output.WithHighLightFormat(extensionMetadata.Id)),
Action: createExtensionDirectoryAction,
}).
AddTask(ux.TaskOptions{
Title: "Build extension",
Action: buildExtensionAction,
}).
AddTask(ux.TaskOptions{
Title: "Package extension",
Action: packageExtensionAction,
}).
AddTask(ux.TaskOptions{
Title: "Publish extension to local extension source",
Action: publishExtensionAction,
}).
AddTask(ux.TaskOptions{
Title: "Install extension",
Action: installExtensionAction,
})
}
if err := taskList.Run(); err != nil {
return fmt.Errorf("failed running init tasks: %w", err)
}
if localRegistryExists {
fmt.Println(output.WithWarningFormat("Local extension source already exists."))
fmt.Println()
}
if !flags.createRegistry {
fmt.Println(output.WithBold("Try out the extension"))
fmt.Printf(
"- Run %s to try your extension now.\n",
output.WithHighLightFormat("azd %s -h", extensionMetadata.Namespace),
)
fmt.Println()
fmt.Println(output.WithBold("Next Steps"))
fmt.Printf(
"- Navigate to the %s directory and start building your extension.\n",
output.WithHighLightFormat(extensionMetadata.Id),
)
fmt.Println()
fmt.Println(output.WithBold("Iterate on the extension"))
fmt.Printf(
"- Run %s to watch for code changes and auto re-build the extension\n",
output.WithHighLightFormat("azd x watch"),
)
fmt.Printf("- Run %s to rebuild the extension\n", output.WithHighLightFormat("azd x build"))
fmt.Println()
fmt.Println(output.WithBold("Package, release and publish the extension"))
fmt.Printf("- Run %s to package the extension\n", output.WithHighLightFormat("azd x pack"))
fmt.Printf("- Run %s to create a GitHub release for your extension\n", output.WithHighLightFormat("azd x release"))
fmt.Printf("- Run %s to publish the extension\n", output.WithHighLightFormat("azd x publish"))
fmt.Println()
}
return nil
}