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()
}