func()

in cli/azd/internal/cmd/deploy.go [172:327]


func (da *DeployAction) Run(ctx context.Context) (*actions.ActionResult, error) {
	targetServiceName := da.flags.serviceName
	if len(da.args) == 1 {
		targetServiceName = da.args[0]
	}

	serviceNameWarningCheck(da.console, da.flags.serviceName, "deploy")

	if da.env.GetSubscriptionId() == "" {
		return nil, errors.New(
			"infrastructure has not been provisioned. Run `azd provision`",
		)
	}

	targetServiceName, err := getTargetServiceName(
		ctx,
		da.projectManager,
		da.importManager,
		da.projectConfig,
		string(project.ServiceEventDeploy),
		targetServiceName,
		da.flags.All,
	)
	if err != nil {
		return nil, err
	}

	if da.flags.All && da.flags.fromPackage != "" {
		return nil, errors.New(
			"'--from-package' cannot be specified when '--all' is set. Specify a specific service by passing a <service>")
	}

	if targetServiceName == "" && da.flags.fromPackage != "" {
		return nil, errors.New(
			//nolint:lll
			"'--from-package' cannot be specified when deploying all services. Specify a specific service by passing a <service>",
		)
	}

	if err := da.projectManager.Initialize(ctx, da.projectConfig); err != nil {
		return nil, err
	}

	if err := da.projectManager.EnsureServiceTargetTools(ctx, da.projectConfig, func(svc *project.ServiceConfig) bool {
		return targetServiceName == "" || svc.Name == targetServiceName
	}); err != nil {
		return nil, err
	}

	// Command title
	da.console.MessageUxItem(ctx, &ux.MessageTitle{
		Title: "Deploying services (azd deploy)",
	})

	startTime := time.Now()

	deployResults := map[string]*project.ServiceDeployResult{}
	stableServices, err := da.importManager.ServiceStable(ctx, da.projectConfig)
	if err != nil {
		return nil, err
	}

	for _, svc := range stableServices {
		stepMessage := fmt.Sprintf("Deploying service %s", svc.Name)
		da.console.ShowSpinner(ctx, stepMessage, input.Step)

		// Skip this service if both cases are true:
		// 1. The user specified a service name
		// 2. This service is not the one the user specified
		if targetServiceName != "" && targetServiceName != svc.Name {
			da.console.StopSpinner(ctx, stepMessage, input.StepSkipped)
			continue
		}

		if alphaFeatureId, isAlphaFeature := alpha.IsFeatureKey(string(svc.Host)); isAlphaFeature {
			// alpha feature on/off detection for host is done during initialization.
			// This is just for displaying the warning during deployment.
			da.console.WarnForFeature(ctx, alphaFeatureId)
		}

		var packageResult *project.ServicePackageResult
		if da.flags.fromPackage != "" {
			// --from-package set, skip packaging
			packageResult = &project.ServicePackageResult{
				PackagePath: da.flags.fromPackage,
			}
		} else {
			//  --from-package not set, package the application
			packageResult, err = async.RunWithProgress(
				func(packageProgress project.ServiceProgress) {
					progressMessage := fmt.Sprintf("Deploying service %s (%s)", svc.Name, packageProgress.Message)
					da.console.ShowSpinner(ctx, progressMessage, input.Step)
				},
				func(progress *async.Progress[project.ServiceProgress]) (*project.ServicePackageResult, error) {
					return da.serviceManager.Package(ctx, svc, nil, progress, nil)
				},
			)

			// do not stop progress here as next step is to deploy
			if err != nil {
				da.console.StopSpinner(ctx, stepMessage, input.StepFailed)
				return nil, err
			}
		}

		deployResult, err := async.RunWithProgress(
			func(deployProgress project.ServiceProgress) {
				progressMessage := fmt.Sprintf("Deploying service %s (%s)", svc.Name, deployProgress.Message)
				da.console.ShowSpinner(ctx, progressMessage, input.Step)
			},
			func(progress *async.Progress[project.ServiceProgress]) (*project.ServiceDeployResult, error) {
				return da.serviceManager.Deploy(ctx, svc, packageResult, progress)
			},
		)

		da.console.StopSpinner(ctx, stepMessage, input.GetStepResultFormat(err))
		if err != nil {
			return nil, err
		}

		deployResults[svc.Name] = deployResult

		// report deploy outputs
		da.console.MessageUxItem(ctx, deployResult)
	}

	aspireDashboardUrl := apphost.AspireDashboardUrl(ctx, da.env, da.alphaFeatureManager)
	if aspireDashboardUrl != nil {
		da.console.MessageUxItem(ctx, aspireDashboardUrl)
	}

	if da.formatter.Kind() == output.JsonFormat {
		deployResult := DeploymentResult{
			Timestamp: time.Now(),
			Services:  deployResults,
		}

		if fmtErr := da.formatter.Format(deployResult, da.writer, nil); fmtErr != nil {
			return nil, fmt.Errorf("deploy result could not be displayed: %w", fmtErr)
		}
	}

	return &actions.ActionResult{
		Message: &actions.ResultMessage{
			Header: fmt.Sprintf("Your application was deployed to Azure in %s.", ux.DurationAsText(since(startTime))),
			FollowUp: getResourceGroupFollowUp(ctx,
				da.formatter,
				da.portalUrlBase,
				da.projectConfig,
				da.resourceManager,
				da.env,
				false,
			),
		},
	}, nil
}