func runPublishAction()

in cli/azd/extensions/microsoft.azd.extensions/internal/cmd/publish.go [82:304]


func runPublishAction(ctx context.Context, flags *publishFlags) error {
	absExtensionPath, err := os.Getwd()
	if err != nil {
		return fmt.Errorf("failed to get absolute path for extension directory: %w", err)
	}

	extensionMetadata, err := models.LoadExtension(absExtensionPath)
	if err != nil {
		return err
	}

	if flags.version == "" {
		flags.version = extensionMetadata.Version
	}

	if flags.artifacts == "" {
		localRegistryArtifactsPath, err := internal.LocalRegistryArtifactsPath()
		if err != nil {
			return err
		}

		flags.artifacts = filepath.Join(localRegistryArtifactsPath, extensionMetadata.Id, flags.version, "*.zip")
	}

	// Setting remote repository overrides local artifacts
	if flags.repository != "" {
		flags.artifacts = ""
	}

	var release *githubRelease
	artifactMap := map[string]extensions.ExtensionArtifact{}
	assets := []*githubReleaseAsset{}

	tagName := fmt.Sprintf("azd-ext-%s_%s", extensionMetadata.SafeDashId(), flags.version)

	absRegistryPath, err := filepath.Abs(flags.registryPath)
	if err != nil {
		return err
	}

	fmt.Println()

	if flags.repository != "" {
		repo, err := getGithubRepo(absExtensionPath, flags.repository)
		if err != nil {
			return err
		}

		release, err = getGithubRelease(absExtensionPath, flags.repository, tagName)
		if err != nil {
			return err
		}

		fmt.Printf("%s: %s - %s\n",
			output.WithBold("GitHub Repo"),
			repo.Name,
			output.WithHyperlink(repo.Url, "View Repo"),
		)
		fmt.Printf("%s: %s (%s) - %s\n",
			output.WithBold("GitHub Release"),
			release.Name,
			release.TagName,
			output.WithHyperlink(release.Url, "View Release"),
		)
	} else {
		fmt.Printf("%s: %s\n", output.WithBold("Artifacts"), flags.artifacts)
	}

	fmt.Printf("%s: %s\n", output.WithBold("Registry"), output.WithHyperlink(absRegistryPath, absRegistryPath))

	taskList := ux.NewTaskList(nil).
		AddTask(ux.TaskOptions{
			Title: "Fetching local artifacts",
			Action: func(spf ux.SetProgressFunc) (ux.TaskState, error) {
				if flags.artifacts == "" {
					return ux.Skipped, nil
				}

				files, err := filepath.Glob(flags.artifacts)
				if err != nil {
					return ux.Error, common.NewDetailedError(
						"Failed to list artifacts",
						fmt.Errorf("failed to list artifacts: %w", err),
					)
				}

				if len(files) == 0 {
					return ux.Error, common.NewDetailedError(
						"Artifacts not found",
						fmt.Errorf("no artifacts found at path: %s", flags.artifacts),
					)
				}

				for _, file := range files {
					fileInfo, err := os.Stat(file)
					if err != nil {
						return ux.Error, common.NewDetailedError(
							"Failed to get file info",
							fmt.Errorf("failed to get file info: %w", err),
						)
					}

					absFilePath, err := filepath.Abs(file)
					if err != nil {
						return ux.Error, common.NewDetailedError(
							"Failed to get absolute file path",
							fmt.Errorf("failed to get absolute file path: %w", err),
						)
					}

					assets = append(assets, &githubReleaseAsset{
						Name: filepath.Base(file),
						Path: absFilePath,
						Size: fileInfo.Size(),
					})
				}

				return ux.Success, nil
			},
		}).
		AddTask(ux.TaskOptions{
			Title: "Fetching GitHub release assets",
			Action: func(spf ux.SetProgressFunc) (ux.TaskState, error) {
				if flags.repository == "" {
					return ux.Skipped, nil
				}

				for _, asset := range release.Assets {
					spf(fmt.Sprintf("Processing %s", asset.Name))
					tempPath, err := internal.DownloadAssetToTemp(asset.Url, asset.Name)
					if err != nil {
						return ux.Error, common.NewDetailedError(
							"Failed to download asset",
							fmt.Errorf("failed to download asset: %w", err),
						)
					}

					asset.Path = tempPath
					assets = append(assets, asset)
				}

				return ux.Success, nil
			},
		}).
		AddTask(ux.TaskOptions{
			Title: "Generating extension metadata",
			Action: func(spf ux.SetProgressFunc) (ux.TaskState, error) {
				for _, asset := range assets {
					spf(fmt.Sprintf("Processing %s", asset.Name))

					osArch, err := internal.InferOSArch(asset.Name)
					if err != nil {
						return ux.Error, common.NewDetailedError(
							"Invalid asset name",
							fmt.Errorf("failed to infer OS and architecture from asset name: %w", err),
						)
					}

					// Compute checksum
					checksum, err := internal.ComputeChecksum(asset.Path)
					if err != nil {
						return ux.Error, common.NewDetailedError(
							"Failed to compute checksum",
							fmt.Errorf("failed to compute checksum: %w", err),
						)
					}

					artifactMetadata, err := createPlatformMetadata(extensionMetadata, osArch, asset.Name)
					if err != nil {
						return ux.Error, common.NewDetailedError(
							"Failed to create platform metadata",
							fmt.Errorf("failed to create platform metadata: %w", err),
						)
					}

					artifactPath := asset.Url
					if artifactPath == "" {
						artifactPath = asset.Path
					}

					artifactMap[osArch] = extensions.ExtensionArtifact{
						URL: artifactPath,
						Checksum: extensions.ExtensionChecksum{
							Algorithm: "sha256",
							Value:     checksum,
						},
						AdditionalMetadata: artifactMetadata,
					}

					// Remove temp file assets that were downloaded and processed.
					if asset.Url != "" && asset.Path != "" {
						defer os.Remove(asset.Path)
					}
				}

				return ux.Success, nil
			},
		}).
		AddTask(ux.TaskOptions{
			Title: "Updating extension source registry",
			Action: func(spf ux.SetProgressFunc) (ux.TaskState, error) {
				registry, err := models.LoadRegistry(flags.registryPath)
				if err != nil {
					return ux.Error, common.NewDetailedError(
						"Failed to load registry",
						fmt.Errorf("failed to load registry: %w", err),
					)
				}

				addOrUpdateExtension(registry, extensionMetadata, artifactMap)
				if err := saveRegistry(flags.registryPath, registry); err != nil {
					return ux.Error, common.NewDetailedError(
						"Failed to save registry",
						fmt.Errorf("failed to save registry: %w", err),
					)
				}

				return ux.Success, nil
			},
		})

	return taskList.Run()
}