diff --git a/cli/azd/CHANGELOG.md b/cli/azd/CHANGELOG.md index 6aba6c5601a..6b52a1f26f9 100644 --- a/cli/azd/CHANGELOG.md +++ b/cli/azd/CHANGELOG.md @@ -2,6 +2,10 @@ ## 1.30.0-beta.1 (Unreleased) +### Other Changes + +- Rename the `azd extension upgrade` and `azd tool upgrade` commands to `azd extension update` and `azd tool update`. The former `upgrade` names continue to work as aliases for backward compatibility. + ## 1.29.0 (2026-07-29) ### Features Added diff --git a/cli/azd/cmd/auto_install_test.go b/cli/azd/cmd/auto_install_test.go index 6358bb3f04f..19ce1fd34a7 100644 --- a/cli/azd/cmd/auto_install_test.go +++ b/cli/azd/cmd/auto_install_test.go @@ -2124,7 +2124,7 @@ func TestProjectExtensionErrorsCarrySuggestions(t *testing.T) { suggestErr, ok := errors.AsType[*internal.ErrorWithSuggestion](err) require.True(t, ok, "expected an ErrorWithSuggestion") assert.Contains(t, suggestErr.Error(), "does not satisfy constraint") - assert.Contains(t, suggestErr.Suggestion, "azd extension upgrade microsoft.foundry") + assert.Contains(t, suggestErr.Suggestion, "azd extension update microsoft.foundry") assert.NotContains(t, suggestErr.Suggestion, "--version >=1.0.0") }) diff --git a/cli/azd/cmd/extension.go b/cli/azd/cmd/extension.go index c3ed8e82220..791ddf9c1c2 100644 --- a/cli/azd/cmd/extension.go +++ b/cli/azd/cmd/extension.go @@ -114,32 +114,33 @@ tracked for updates; reinstall from a newer bundle to update.`, FlagsResolver: newExtensionUninstallFlags, }) - // azd extension upgrade - group.Add("upgrade", &actions.ActionDescriptorOptions{ + // azd extension update + group.Add("update", &actions.ActionDescriptorOptions{ Command: &cobra.Command{ - Use: "upgrade [extension-id]", - Short: "Upgrade installed extensions to the latest version.", - Long: `Upgrade one or more installed extensions. + Use: "update [extension-id]", + Aliases: []string{"upgrade"}, + Short: "Update installed extensions to the latest version.", + Long: `Update one or more installed extensions. By default, uses the stored registry source for each extension. If the stored source is unavailable, falls back to the main (azd) registry. Extensions that were installed from a non-main registry (e.g., dev) are automatically promoted to the main registry when a newer version is available there. -Use --source to override the registry source for the upgrade. It accepts a +Use --source to override the registry source for the update. It accepts a registered source name or registry location (URL or file path); locations are -registered first and the upgraded extension's stored source is updated. Because +registered first and the updated extension's stored source is updated. Because registration is interactive, locations are rejected under --no-prompt. Use --all -to upgrade all installed extensions in a single batch; failures in one extension -do not prevent the remaining extensions from being upgraded. +to update all installed extensions in a single batch; failures in one extension +do not prevent the remaining extensions from being updated. -When upgrading an extension that has dependencies, any installed -dependencies are automatically upgraded too, to the highest version +When updating an extension that has dependencies, any installed +dependencies are automatically updated too, to the highest version satisfying the extension's declared constraints. Use ---no-dependency-upgrades to opt out and upgrade only the named +--no-dependency-upgrades to opt out and update only the named extension. -Use --output json for a structured report of all upgrade results.`, +Use --output json for a structured report of all update results.`, }, OutputFormats: []output.Format{output.JsonFormat, output.NoneFormat}, DefaultFormat: output.NoneFormat, @@ -169,7 +170,7 @@ Use --output json for a structured report of all upgrade results.`, Use: "add", Short: "Add an extension source with the specified name", Long: "Add an extension source with the specified name.\n\n" + - "`azd extension install --source` and `azd extension upgrade --source` also accept " + + "`azd extension install --source` and `azd extension update --source` also accept " + "a registry URL or file path directly.", }, ActionResolver: newExtensionSourceAddAction, @@ -484,9 +485,9 @@ func (a *extensionListAction) Run(ctx context.Context) (*actions.ActionResult, e if hasCompatibleUpdates { a.console.Message(ctx, fmt.Sprintf( - "To upgrade: %s", output.WithHighLightFormat("azd extension upgrade "))) + "To update: %s", output.WithHighLightFormat("azd extension update "))) a.console.Message(ctx, fmt.Sprintf( - "To upgrade all: %s", output.WithHighLightFormat("azd extension upgrade --all"))) + "To update all: %s", output.WithHighLightFormat("azd extension update --all"))) } if hasIncompatibleUpdates { @@ -507,7 +508,7 @@ func (a *extensionListAction) Run(ctx context.Context) (*actions.ActionResult, e // Status indicator constants for extension list display. const ( statusUpToDate = "Up to date" - statusUpgrade = "Upgrade available" + statusUpgrade = "Update available" statusIncompat = "Incompatible" statusNotInstall = "Not installed" ) @@ -1057,7 +1058,7 @@ func (a *extensionInstallAction) Run(ctx context.Context) (*actions.ActionResult ) if err != nil { a.console.StopSpinner(ctx, stepMessage, input.StepFailed) - return nil, wrapDependencyError(fmt.Errorf("failed to upgrade extension: %w", err)) + return nil, wrapDependencyError(fmt.Errorf("failed to update extension: %w", err)) } stepMessage += output.WithGrayFormat(" (%s)", extensionVersion.Version) @@ -1137,7 +1138,7 @@ func (a *extensionInstallAction) sourceDisplayLabelForInstalled(source string) s // versionTransitionVerb returns a capitalized verb phrase describing the move // from the installed version to the target version: "Reinstall" when they match, -// "Upgrade to " / "Downgrade to " when both parse as semver, and +// "Update to " / "Downgrade to " when both parse as semver, and // a neutral "Replace with " when ordering is undefined (non-semver tags). func versionTransitionVerb(installedVersion, targetVersion string) string { if installedVersion == targetVersion { @@ -1150,7 +1151,7 @@ func versionTransitionVerb(installedVersion, targetVersion string) string { case installedErr == nil && targetErr == nil && targetSemver.LessThan(installedSemver): return fmt.Sprintf("Downgrade to %s", targetVersion) case installedErr == nil && targetErr == nil && targetSemver.GreaterThan(installedSemver): - return fmt.Sprintf("Upgrade to %s", targetVersion) + return fmt.Sprintf("Update to %s", targetVersion) default: return fmt.Sprintf("Replace with %s", targetVersion) } @@ -1852,17 +1853,17 @@ func newExtensionUpgradeFlags(cmd *cobra.Command, global *internal.GlobalCommand flags := &extensionUpgradeFlags{ global: global, } - cmd.Flags().StringVarP(&flags.version, "version", "v", "", "The version of the extension to upgrade to") + cmd.Flags().StringVarP(&flags.version, "version", "v", "", "The version of the extension to update to") cmd.Flags().StringVarP(&flags.source, "source", "s", "", - "The registered source name or registry location (URL or file path) to use for upgrades.") - cmd.Flags().BoolVar(&flags.all, "all", false, "Upgrade all installed extensions") + "The registered source name or registry location (URL or file path) to use for updates.") + cmd.Flags().BoolVar(&flags.all, "all", false, "Update all installed extensions") cmd.Flags().BoolVar(&flags.noDependencyUpgrades, "no-dependency-upgrades", false, - "Do not upgrade dependencies when upgrading an extension that has dependencies") + "Do not update dependencies when updating an extension that has dependencies") return flags } -// azd extension upgrade +// azd extension update type extensionUpgradeAction struct { args []string flags *extensionUpgradeFlags @@ -1902,8 +1903,8 @@ func (a *extensionUpgradeAction) Run( Err: fmt.Errorf( "cannot specify both an extension name and --all flag: %w", internal.ErrInvalidFlagCombination), - Suggestion: "Use either 'azd extension upgrade ' " + - "or 'azd extension upgrade --all'.", + Suggestion: "Use either 'azd extension update ' " + + "or 'azd extension update --all'.", } } @@ -1912,7 +1913,7 @@ func (a *extensionUpgradeAction) Run( Err: fmt.Errorf( "cannot specify --version with multiple extensions: %w", internal.ErrInvalidFlagCombination), - Suggestion: "Upgrade one extension at a time when " + + Suggestion: "Update one extension at a time when " + "using --version.", } } @@ -1927,8 +1928,8 @@ func (a *extensionUpgradeAction) Run( if len(a.args) == 0 && !a.flags.all { return nil, &internal.ErrorWithSuggestion{ Err: internal.ErrNoArgsProvided, - Suggestion: "Run 'azd extension upgrade '" + - " or 'azd extension upgrade --all'.", + Suggestion: "Run 'azd extension update '" + + " or 'azd extension update --all'.", } } @@ -1936,9 +1937,9 @@ func (a *extensionUpgradeAction) Run( if !isJsonOutput { a.console.MessageUxItem(ctx, &ux.MessageTitle{ - Title: "Upgrade azd extensions " + - "(azd extension upgrade)", - TitleNote: "Upgrades the specified extensions " + + Title: "Update azd extensions " + + "(azd extension update)", + TitleNote: "Updates the specified extensions " + "on the local machine", }) } @@ -2010,7 +2011,7 @@ loop: report, a.writer, nil, ); err != nil { return nil, fmt.Errorf( - "failed to format upgrade report: %w", err, + "failed to format update report: %w", err, ) } return upgradeActionResult(results) @@ -2066,7 +2067,7 @@ func upgradeVersionResolutionError(extensionId, version, source string) error { // upgradeRetryCommand returns a retry command that preserves the source and // version explicitly requested by the user. func upgradeRetryCommand(extensionId, source, version string) string { - command := fmt.Sprintf("azd extension upgrade %s", extensionId) + command := fmt.Sprintf("azd extension update %s", extensionId) if source != "" { command += fmt.Sprintf(" --source %s", source) } @@ -2103,8 +2104,8 @@ func (a *extensionUpgradeAction) upgradeOneExtension( startTime := time.Now() baseResult := extensions.UpgradeResult{ExtensionId: extensionId} - // Start a telemetry span for this individual extension upgrade. - ctx, span := tracing.Start(ctx, events.ExtensionUpgradeEvent) + // Start a telemetry span for this individual extension update. + ctx, span := tracing.Start(ctx, events.ExtensionUpdateEvent) defer func() { elapsed := time.Since(startTime).Milliseconds() span.SetAttributes( @@ -2118,16 +2119,16 @@ func (a *extensionUpgradeAction) upgradeOneExtension( fields.ExtensionSource.String( baseResult.ToSource, ), - fields.ExtensionUpgradeDurationMs.Int64(elapsed), - fields.ExtensionUpgradeOutcome.String( + fields.ExtensionUpdateDurationMs.Int64(elapsed), + fields.ExtensionUpdateOutcome.String( baseResult.Status.String(), ), - fields.ExtensionDependencyUpgradeCount.Int( + fields.ExtensionDependencyUpdateCount.Int( extensions.CountDependencyUpgrades(baseResult.DependencyUpgrades), ), ) if baseResult.Status == extensions.UpgradeStatusFailed { - span.SetStatus(codes.Error, "upgrade.failed") + span.SetStatus(codes.Error, "update.failed") } else { span.SetStatus(codes.Ok, "") } @@ -2139,7 +2140,7 @@ func (a *extensionUpgradeAction) upgradeOneExtension( } stepMsg := fmt.Sprintf( - "Upgrading %s extension", + "Updating %s extension", output.WithHighLightFormat(extensionId), ) if !isJsonOutput { @@ -2197,7 +2198,7 @@ func (a *extensionUpgradeAction) upgradeOneExtension( "reinstall with a newer bundle to update" if !isJsonOutput { skipMsg := fmt.Sprintf( - "Upgrading %s extension", + "Updating %s extension", output.WithHighLightFormat(extensionId), ) + output.WithGrayFormat( " (Installed from a bundle)", @@ -2299,7 +2300,7 @@ func (a *extensionUpgradeAction) upgradeOneExtension( } if !isJsonOutput { skipMsg := fmt.Sprintf( - "Upgrading %s extension", + "Updating %s extension", output.WithHighLightFormat(extensionId), ) + output.WithGrayFormat( " (No longer available in any registry)", @@ -2439,7 +2440,7 @@ func (a *extensionUpgradeAction) upgradeOneExtension( baseResult.SkipReason = "already up to date" if !isJsonOutput { skipMsg := stepMsg + output.WithGrayFormat( - " (No upgrade available)", + " (No update available)", ) a.console.StopSpinner( ctx, skipMsg, input.StepSkipped, @@ -2460,13 +2461,13 @@ func (a *extensionUpgradeAction) upgradeOneExtension( if err != nil { if isNetworkError(err) { return fail(fmt.Errorf( - "network error upgrading %s "+ + "network error updating %s "+ "(check your connection and retry): %w", extensionId, err, )) } return fail(fmt.Errorf( - "failed to upgrade extension: %w", err, + "failed to update extension: %w", err, )) } baseResult.ToVersion = extVersion.Version @@ -2493,7 +2494,7 @@ func (a *extensionUpgradeAction) upgradeOneExtension( if !isJsonOutput { doneMsg := fmt.Sprintf( - "Upgraded %s extension %s", + "Updated %s extension %s", output.WithHighLightFormat(extensionId), output.WithGrayFormat( "(%s \u2192 %s)", @@ -2523,7 +2524,7 @@ func (a *extensionUpgradeAction) displayPromotionWarning( ) { a.console.StopSpinner(ctx, stepMsg, input.StepWarning) a.console.Message(ctx, output.WithWarningFormat( - " (!) Warning: Upgraded %s extension (%s \u2192 %s, %s \u2192 %s registry)", + " (!) Warning: Updated %s extension (%s \u2192 %s, %s \u2192 %s registry)", output.WithHighLightFormat(extensionId), fromVersion, toVersion, output.WithHighLightFormat(oldSource), @@ -2575,7 +2576,7 @@ func displayDependencyUpgradeResults( case extensions.UpgradeStatusFailed: suggestionPadding = len("(x) Failed: ") console.Message(ctx, fmt.Sprintf( - "%s%s Upgrading %s dependency%s", + "%s%s Updating %s dependency%s", indent, output.WithErrorFormat("(x) Failed:"), output.WithHighLightFormat(child.ExtensionId), @@ -2591,7 +2592,7 @@ func displayDependencyUpgradeResults( case extensions.UpgradeStatusSkipped: suggestionPadding = len("(-) Skipped: ") line := fmt.Sprintf( - "%s%s Upgrading %s dependency", + "%s%s Updating %s dependency", indent, output.WithGrayFormat("(-) Skipped:"), output.WithHighLightFormat(child.ExtensionId), @@ -2622,7 +2623,7 @@ func dependencyChangeVerb(fromVersion, toVersion string) string { if to.LessThan(from) { return "Downgraded" } - return "Upgraded" + return "Updated" } // displayUpgradeSummary prints the batch summary line after all @@ -2639,7 +2640,7 @@ func displayUpgradeSummary( depUpgraded := summary.DependencyUpgradesByStatus[extensions.UpgradeStatusUpgraded] if summary.Upgraded > 0 { upgradedPart := output.WithSuccessFormat( - "%d upgraded", summary.Upgraded, + "%d updated", summary.Upgraded, ) if depUpgraded > 0 { noun := "dependency" @@ -2685,7 +2686,7 @@ func displayUpgradeSummary( console.Message(ctx, fmt.Sprintf( " Run '%s' to retry failed extensions.", output.WithHighLightFormat( - "azd extension upgrade ", + "azd extension update ", ), )) } @@ -2702,19 +2703,19 @@ func upgradeActionResult( return &actions.ActionResult{ Message: &actions.ResultMessage{ Header: fmt.Sprintf( - "%d of %d extensions failed to upgrade", + "%d of %d extensions failed to update", summary.Failed, summary.Total, ), }, }, fmt.Errorf( - "%d of %d extensions failed to upgrade", + "%d of %d extensions failed to update", summary.Failed, summary.Total, ) } return &actions.ActionResult{ Message: &actions.ResultMessage{ - Header: "Extensions upgraded successfully", + Header: "Extensions updated successfully", }, }, nil } diff --git a/cli/azd/cmd/extension_bundle_test.go b/cli/azd/cmd/extension_bundle_test.go index 5de4ee44203..ed0e51ab868 100644 --- a/cli/azd/cmd/extension_bundle_test.go +++ b/cli/azd/cmd/extension_bundle_test.go @@ -188,7 +188,7 @@ func TestConfirmSourceChange(t *testing.T) { `azure.ai.agents 1.0.0 is already installed from source "azd". Reinstall from bundle?`) }) - t.Run("UpgradeShowsTargetVersion", func(t *testing.T) { + t.Run("UpdateShowsTargetVersion", func(t *testing.T) { console := mockinput.NewMockConsole() console.WhenConfirm(func(input.ConsoleOptions) bool { return true }).Respond(true) action := newConfirmTestAction(console, false) @@ -199,7 +199,7 @@ func TestConfirmSourceChange(t *testing.T) { require.NoError(t, err) require.True(t, proceed) require.Contains(t, lastConfirmMessage(console), - `azure.ai.agents 1.0.0 is already installed from source "azd". Upgrade to 2.0.0 from bundle?`) + `azure.ai.agents 1.0.0 is already installed from source "azd". Update to 2.0.0 from bundle?`) }) t.Run("DowngradeDeclined", func(t *testing.T) { @@ -310,9 +310,9 @@ func TestVersionTransitionVerb(t *testing.T) { expected string }{ {"1.0.0", "1.0.0", "Reinstall"}, - {"1.0.0", "2.0.0", "Upgrade to 2.0.0"}, + {"1.0.0", "2.0.0", "Update to 2.0.0"}, {"1.0.0", "0.9.0", "Downgrade to 0.9.0"}, - {"1.0.0-preview", "1.0.0", "Upgrade to 1.0.0"}, + {"1.0.0-preview", "1.0.0", "Update to 1.0.0"}, // Non-semver tags have no defined ordering -> neutral verb. {"nightly", "1.0.0", "Replace with 1.0.0"}, {"1.0.0", "nightly", "Replace with nightly"}, diff --git a/cli/azd/cmd/extension_test.go b/cli/azd/cmd/extension_test.go index 914557eef6d..743f97abdb4 100644 --- a/cli/azd/cmd/extension_test.go +++ b/cli/azd/cmd/extension_test.go @@ -494,7 +494,7 @@ func TestDisplayUpgradeSummary(t *testing.T) { {Status: extensions.UpgradeStatusUpgraded}, }, wantMsgs: []string{ - "2 upgraded", + "2 updated", }, }, { @@ -506,7 +506,7 @@ func TestDisplayUpgradeSummary(t *testing.T) { {Status: extensions.UpgradeStatusFailed}, }, wantMsgs: []string{ - "1 upgraded", + "1 updated", "1 skipped", "1 promoted", "1 failed", @@ -519,7 +519,7 @@ func TestDisplayUpgradeSummary(t *testing.T) { }, wantMsgs: []string{ "1 failed", - "azd extension upgrade ", + "azd extension update ", }, }, { @@ -590,7 +590,7 @@ func TestUpgradeActionResult(t *testing.T) { require.NotNil(t, actionResult) assert.Equal( t, - "Extensions upgraded successfully", + "Extensions updated successfully", actionResult.Message.Header, ) }) @@ -609,7 +609,7 @@ func TestUpgradeActionResult(t *testing.T) { require.NotNil(t, actionResult) assert.Contains( t, err.Error(), - "2 of 3 extensions failed to upgrade", + "2 of 3 extensions failed to update", ) assert.Contains( t, actionResult.Message.Header, @@ -643,7 +643,7 @@ func TestUpgradeActionResult_EmptyResults(t *testing.T) { require.NotNil(t, actionResult) assert.Equal( t, - "Extensions upgraded successfully", + "Extensions updated successfully", actionResult.Message.Header, ) } diff --git a/cli/azd/cmd/extension_upgrade_test.go b/cli/azd/cmd/extension_upgrade_test.go index d9f689f30aa..3e3cf7dce42 100644 --- a/cli/azd/cmd/extension_upgrade_test.go +++ b/cli/azd/cmd/extension_upgrade_test.go @@ -57,23 +57,23 @@ func TestUpgradeRetryCommand(t *testing.T) { }{ { name: "extension only", - want: "azd extension upgrade ext-a", + want: "azd extension update ext-a", }, { name: "source", source: "test", - want: "azd extension upgrade ext-a --source test", + want: "azd extension update ext-a --source test", }, { name: "version", version: "3.0.0", - want: "azd extension upgrade ext-a --version 3.0.0", + want: "azd extension update ext-a --version 3.0.0", }, { name: "source and version", source: "test", version: "3.0.0", - want: "azd extension upgrade ext-a --source test --version 3.0.0", + want: "azd extension update ext-a --source test --version 3.0.0", }, } @@ -209,7 +209,7 @@ func TestUpgradeOneExtension_InteractiveFailurePreservesRetryFlags(t *testing.T) rendered := strings.Join(console.Output(), "\n") require.Contains(t, rendered, result.Error.Error()) - require.Contains(t, rendered, "azd extension upgrade ext-a --source test --version 3.0.0") + require.Contains(t, rendered, "azd extension update ext-a --source test --version 3.0.0") } func TestDisplayDependencyUpgradeResultsFailedSuggestion(t *testing.T) { @@ -291,7 +291,7 @@ func TestDependencyChangeVerb(t *testing.T) { toVersion string want string }{ - {name: "upgrade", fromVersion: "1.0.0", toVersion: "2.0.0", want: "Upgraded"}, + {name: "update", fromVersion: "1.0.0", toVersion: "2.0.0", want: "Updated"}, {name: "downgrade", fromVersion: "2.0.0", toVersion: "1.0.0", want: "Downgraded"}, {name: "non-semver", fromVersion: "nightly", toVersion: "dev", want: "Updated"}, } @@ -407,7 +407,7 @@ func TestUpgradeAction_ContextCancellation(t *testing.T) { // All extensions should be marked as failed require.Error(t, err) require.NotNil(t, result) - assert.Contains(t, err.Error(), "extensions failed to upgrade") + assert.Contains(t, err.Error(), "extensions failed to update") // Parse the JSON output to verify all have failed status var report struct { diff --git a/cli/azd/cmd/middleware/extension_activator.go b/cli/azd/cmd/middleware/extension_activator.go index 3f362d502e8..dce07e97434 100644 --- a/cli/azd/cmd/middleware/extension_activator.go +++ b/cli/azd/cmd/middleware/extension_activator.go @@ -136,7 +136,7 @@ func (a *ExtensionActivator) EnsureProvisioningProviders( Suggestion: fmt.Sprintf( "Run with %s for details, or check for an update with %s", output.WithHighLightFormat("--debug"), - output.WithHighLightFormat("azd extension upgrade %s", ext.Id), + output.WithHighLightFormat("azd extension update %s", ext.Id), ), } } diff --git a/cli/azd/cmd/middleware/extensions.go b/cli/azd/cmd/middleware/extensions.go index 94b0a8ae78f..8faf7d333b6 100644 --- a/cli/azd/cmd/middleware/extensions.go +++ b/cli/azd/cmd/middleware/extensions.go @@ -216,7 +216,7 @@ func (m *ExtensionsMiddleware) Run(ctx context.Context, next NextFn) (*actions.A info.ext.Id, info.result.InstalledVersion, info.result.LatestVersion, )) m.console.Message(ctx, fmt.Sprintf( - "To upgrade extension, run %s", output.WithHighLightFormat("azd extension upgrade %s", info.ext.Id), + "To update the extension, run %s", output.WithHighLightFormat("azd extension update %s", info.ext.Id), )) m.console.Message(ctx, "") } else if len(needsUpdate) > 1 { @@ -230,9 +230,9 @@ func (m *ExtensionsMiddleware) Run(ctx context.Context, next NextFn) (*actions.A )) } m.console.Message(ctx, fmt.Sprintf( - "Run %s to upgrade a specific extension, or %s to upgrade all extensions.", - output.WithHighLightFormat("azd extension upgrade "), - output.WithHighLightFormat("azd extension upgrade --all"), + "Run %s to update a specific extension, or %s to update all extensions.", + output.WithHighLightFormat("azd extension update "), + output.WithHighLightFormat("azd extension update --all"), )) m.console.Message(ctx, "") } diff --git a/cli/azd/cmd/project_extension_auto_install.go b/cli/azd/cmd/project_extension_auto_install.go index bb30dca74d3..332bde450bb 100644 --- a/cli/azd/cmd/project_extension_auto_install.go +++ b/cli/azd/cmd/project_extension_auto_install.go @@ -225,7 +225,7 @@ func validateInstalledExtensionVersion( versionPreference, ), Suggestion: fmt.Sprintf( - "Run 'azd extension upgrade %s' to move to the latest version, or "+ + "Run 'azd extension update %s' to move to the latest version, or "+ "'azd extension install %s --version ' to select an exact version "+ "that satisfies %q.", installed.Id, diff --git a/cli/azd/cmd/telemetry_test.go b/cli/azd/cmd/telemetry_test.go index b8bf78b3251..dff134672dc 100644 --- a/cli/azd/cmd/telemetry_test.go +++ b/cli/azd/cmd/telemetry_test.go @@ -9,9 +9,15 @@ import ( "github.com/stretchr/testify/require" "github.com/azure/azure-dev/cli/azd/internal" + "github.com/azure/azure-dev/cli/azd/internal/tracing/events" "github.com/azure/azure-dev/cli/azd/internal/tracing/fields" ) +func TestTelemetryEventConstants(t *testing.T) { + t.Parallel() + require.Equal(t, "ext.update", events.ExtensionUpdateEvent) +} + // TestTelemetryFieldConstants verifies that all telemetry field constants added for // command-specific instrumentation are properly defined and produce valid attribute // key-value pairs. This is a contract test: if a field constant is removed or renamed, @@ -158,11 +164,11 @@ func TestTelemetryFieldConstants(t *testing.T) { kvFRInstallDuration := fields.ToolFirstRunInstallDurationMsKey.Int64(1234) require.Equal(t, "tool.firstrun.install_duration_ms", string(kvFRInstallDuration.Key)) - kvFromVer := fields.ToolUpgradeFromVersionKey.String("1.0.0") - require.Equal(t, "tool.upgrade.from_version", string(kvFromVer.Key)) + kvFromVer := fields.ToolUpdateFromVersionKey.String("1.0.0") + require.Equal(t, "tool.update.from_version", string(kvFromVer.Key)) - kvToVer := fields.ToolUpgradeToVersionKey.String("1.1.0") - require.Equal(t, "tool.upgrade.to_version", string(kvToVer.Key)) + kvToVer := fields.ToolUpdateToVersionKey.String("1.1.0") + require.Equal(t, "tool.update.to_version", string(kvToVer.Key)) kvUpdates := fields.ToolCheckUpdatesAvailableKey.Int(3) require.Equal(t, "tool.check.updates_available", string(kvUpdates.Key)) @@ -173,6 +179,15 @@ func TestTelemetryFieldConstants(t *testing.T) { kv := fields.ExtensionSourceKind.String("location") require.Equal(t, "extension.source.kind", string(kv.Key)) require.Equal(t, "location", kv.Value.AsString()) + + duration := fields.ExtensionUpdateDurationMs.Int64(1234) + require.Equal(t, "extension.update.duration_ms", string(duration.Key)) + + outcome := fields.ExtensionUpdateOutcome.String("upgraded") + require.Equal(t, "extension.update.outcome", string(outcome.Key)) + + dependencyCount := fields.ExtensionDependencyUpdateCount.Int(2) + require.Equal(t, "extension.dependency_update_count", string(dependencyCount.Key)) }) // Provision validation telemetry fields (emitted by both the Bicep @@ -238,7 +253,7 @@ func TestCommandTelemetryCoverage(t *testing.T) { "extension install", // extension.source.kind "extension list", // extension.source.kind "extension show", // extension.source.kind - "extension upgrade", // extension.source.kind + extension upgrade spans + "extension update", // extension.source.kind + extension update spans "hooks run", // hooks.name, hooks.type "infra generate", // infra.provider "init", // init.method, appinit.* fields @@ -250,7 +265,7 @@ func TestCommandTelemetryCoverage(t *testing.T) { "tool install", // tool.id(s), tool.dry_run, tool.install.* aggregate + per-tool fields "tool show", // tool.id "tool uninstall", // tool.id(s), tool.dry_run, tool.install.* aggregate + per-tool fields - "tool upgrade", // tool.id(s), tool.dry_run, tool.install.* aggregate + tool.upgrade.* versions + "tool update", // tool.id(s), tool.dry_run, tool.install.* aggregate + tool.update.* versions "up", // infra.provider (via provisioning manager; composes provision+deploy) "update", // update.* fields } diff --git a/cli/azd/cmd/testdata/TestFigSpec.ts b/cli/azd/cmd/testdata/TestFigSpec.ts index e05216b7c15..016f0b5f5aa 100644 --- a/cli/azd/cmd/testdata/TestFigSpec.ts +++ b/cli/azd/cmd/testdata/TestFigSpec.ts @@ -6009,20 +6009,20 @@ const completionSpec: Fig.Spec = { }, }, { - name: ['upgrade'], - description: 'Upgrade installed extensions to the latest version.', + name: ['update', 'upgrade'], + description: 'Update installed extensions to the latest version.', options: [ { name: ['--all'], - description: 'Upgrade all installed extensions', + description: 'Update all installed extensions', }, { name: ['--no-dependency-upgrades'], - description: 'Do not upgrade dependencies when upgrading an extension that has dependencies', + description: 'Do not update dependencies when updating an extension that has dependencies', }, { name: ['--source', '-s'], - description: 'The registered source name or registry location (URL or file path) to use for upgrades.', + description: 'The registered source name or registry location (URL or file path) to use for updates.', args: [ { name: 'source', @@ -6031,7 +6031,7 @@ const completionSpec: Fig.Spec = { }, { name: ['--version', '-v'], - description: 'The version of the extension to upgrade to', + description: 'The version of the extension to update to', args: [ { name: 'version', @@ -6515,7 +6515,7 @@ const completionSpec: Fig.Spec = { subcommands: [ { name: ['check'], - description: 'Check for tool upgrades.', + description: 'Check for tool updates.', }, { name: ['install'], @@ -6585,12 +6585,12 @@ const completionSpec: Fig.Spec = { }, }, { - name: ['upgrade'], - description: 'Upgrade installed tools.', + name: ['update', 'upgrade'], + description: 'Update installed tools.', options: [ { name: ['--agent'], - description: 'Upgrade the skill for the specified agent(s): copilot, claude. Use --agent all for every detected agent (skill tools only)', + description: 'Update the skill for the specified agent(s): copilot, claude. Use --agent all for every detected agent (skill tools only)', isRepeatable: true, args: [ { @@ -6600,11 +6600,11 @@ const completionSpec: Fig.Spec = { }, { name: ['--all'], - description: 'Upgrade all installed tools', + description: 'Update all installed tools', }, { name: ['--dry-run'], - description: 'Preview what would be upgraded without making changes', + description: 'Preview what would be updated without making changes', }, ], args: { diff --git a/cli/azd/cmd/testdata/TestUsage-azd-extension-upgrade.snap b/cli/azd/cmd/testdata/TestUsage-azd-extension-update.snap similarity index 64% rename from cli/azd/cmd/testdata/TestUsage-azd-extension-upgrade.snap rename to cli/azd/cmd/testdata/TestUsage-azd-extension-update.snap index d041b100383..9689ef97559 100644 --- a/cli/azd/cmd/testdata/TestUsage-azd-extension-upgrade.snap +++ b/cli/azd/cmd/testdata/TestUsage-azd-extension-update.snap @@ -1,21 +1,21 @@ -Upgrade installed extensions to the latest version. +Update installed extensions to the latest version. Usage - azd extension upgrade [extension-id] [flags] + azd extension update [extension-id] [flags] Flags - --all : Upgrade all installed extensions - --no-dependency-upgrades : Do not upgrade dependencies when upgrading an extension that has dependencies - -s, --source string : The registered source name or registry location (URL or file path) to use for upgrades. - -v, --version string : The version of the extension to upgrade to + --all : Update all installed extensions + --no-dependency-upgrades : Do not update dependencies when updating an extension that has dependencies + -s, --source string : The registered source name or registry location (URL or file path) to use for updates. + -v, --version string : The version of the extension to update to Global Flags -C, --cwd string : Sets the current working directory. --debug : Enables debugging and diagnostics logging. - --docs : Opens the documentation for azd extension upgrade in your web browser. + --docs : Opens the documentation for azd extension update in your web browser. -e, --environment string : The name of the environment to use. - -h, --help : Gets help for upgrade. + -h, --help : Gets help for update. --no-prompt : Runs without prompts. Uses existing values; fails if any required value or decision cannot be resolved automatically. Automatically enabled when azd detects a CI/CD or AI-agent environment; set AZD_NON_INTERACTIVE=false to opt out of that automatic enablement. Find a bug? Want to let us know how we're doing? Fill out this brief survey: https://aka.ms/azure-dev/hats. diff --git a/cli/azd/cmd/testdata/TestUsage-azd-extension.snap b/cli/azd/cmd/testdata/TestUsage-azd-extension.snap index 6a42e9cc5d4..42e82948f3a 100644 --- a/cli/azd/cmd/testdata/TestUsage-azd-extension.snap +++ b/cli/azd/cmd/testdata/TestUsage-azd-extension.snap @@ -10,7 +10,7 @@ Available Commands show : Show details for a specific extension. source : View and manage extension sources uninstall : Uninstall specified extensions. - upgrade : Upgrade installed extensions to the latest version. + update : Update installed extensions to the latest version. Global Flags -C, --cwd string : Sets the current working directory. diff --git a/cli/azd/cmd/testdata/TestUsage-azd-tool-check.snap b/cli/azd/cmd/testdata/TestUsage-azd-tool-check.snap index 219b2328cc6..a9a05d9ded0 100644 --- a/cli/azd/cmd/testdata/TestUsage-azd-tool-check.snap +++ b/cli/azd/cmd/testdata/TestUsage-azd-tool-check.snap @@ -1,5 +1,5 @@ -Check for tool upgrades. +Check for tool updates. Usage azd tool check [flags] diff --git a/cli/azd/cmd/testdata/TestUsage-azd-tool-upgrade.snap b/cli/azd/cmd/testdata/TestUsage-azd-tool-update.snap similarity index 61% rename from cli/azd/cmd/testdata/TestUsage-azd-tool-upgrade.snap rename to cli/azd/cmd/testdata/TestUsage-azd-tool-update.snap index d5d6bed8209..7cf99619396 100644 --- a/cli/azd/cmd/testdata/TestUsage-azd-tool-upgrade.snap +++ b/cli/azd/cmd/testdata/TestUsage-azd-tool-update.snap @@ -1,20 +1,20 @@ -Upgrade installed tools. +Update installed tools. Usage - azd tool upgrade [tool-name...] [flags] + azd tool update [tool-name...] [flags] Flags - --agent strings : Upgrade the skill for the specified agent(s): copilot, claude. Use --agent all for every detected agent (skill tools only) - --all : Upgrade all installed tools - --dry-run : Preview what would be upgraded without making changes + --agent strings : Update the skill for the specified agent(s): copilot, claude. Use --agent all for every detected agent (skill tools only) + --all : Update all installed tools + --dry-run : Preview what would be updated without making changes Global Flags -C, --cwd string : Sets the current working directory. --debug : Enables debugging and diagnostics logging. - --docs : Opens the documentation for azd tool upgrade in your web browser. + --docs : Opens the documentation for azd tool update in your web browser. -e, --environment string : The name of the environment to use. - -h, --help : Gets help for upgrade. + -h, --help : Gets help for update. --no-prompt : Runs without prompts. Uses existing values; fails if any required value or decision cannot be resolved automatically. Automatically enabled when azd detects a CI/CD or AI-agent environment; set AZD_NON_INTERACTIVE=false to opt out of that automatic enablement. Find a bug? Want to let us know how we're doing? Fill out this brief survey: https://aka.ms/azure-dev/hats. diff --git a/cli/azd/cmd/testdata/TestUsage-azd-tool.snap b/cli/azd/cmd/testdata/TestUsage-azd-tool.snap index 1f201972839..d7b8a2cad72 100644 --- a/cli/azd/cmd/testdata/TestUsage-azd-tool.snap +++ b/cli/azd/cmd/testdata/TestUsage-azd-tool.snap @@ -5,12 +5,12 @@ Usage azd tool [command] Available Commands - check : Check for tool upgrades. + check : Check for tool updates. install : Install specified tools. list : List all tools with status. show : Show details for a specific tool. uninstall : Uninstall installed tools. - upgrade : Upgrade installed tools. + update : Update installed tools. Global Flags -C, --cwd string : Sets the current working directory. diff --git a/cli/azd/cmd/tool.go b/cli/azd/cmd/tool.go index ac668528fdb..ebf3a4c7d30 100644 --- a/cli/azd/cmd/tool.go +++ b/cli/azd/cmd/tool.go @@ -28,9 +28,9 @@ import ( ) // singleResultCommonAttrs returns the usage attributes shared by single-target -// `azd tool install` and `azd tool upgrade`: success, tool.id, and the -// installation strategy. Callers append upgrade-specific version attrs -// (tool.upgrade.{from,to}_version) on top. +// `azd tool install` and `azd tool update`: success, tool.id, and the +// installation strategy. Callers append update-specific version attrs +// (tool.update.{from,to}_version) on top. // // Returns nil if r is nil so callers can safely pass through results without // pre-validating the slice element. @@ -53,7 +53,7 @@ func singleResultCommonAttrs(r *tool.InstallResult) []attribute.KeyValue { // emitToolInstallTelemetry emits aggregate telemetry attributes for a batch // install or upgrade operation. When the batch contains exactly one tool the // caller is responsible for also emitting tool.id, tool.install.strategy, and -// tool.install.success (and, for upgrades, tool.upgrade.{from,to}_version). +// tool.install.success (and, for updates, tool.update.{from,to}_version). // // When the batch infrastructure itself fails (opErr != nil and results is // empty) every requested tool is counted as a failure and its ID is added to @@ -93,7 +93,7 @@ func toolActions(root *actions.ActionDescriptor) *actions.ActionDescriptor { toolCmd := &cobra.Command{ Use: "tool", Short: "Manage Azure development tools.", - Long: "Discover, install, upgrade, and check status of Azure development tools.", + Long: "Discover, install, update, and check status of Azure development tools.", } group := root.Add("tool", &actions.ActionDescriptorOptions{ @@ -127,11 +127,12 @@ func toolActions(root *actions.ActionDescriptor) *actions.ActionDescriptor { FlagsResolver: newToolInstallFlags, }) - // azd tool upgrade [tool-name...] - group.Add("upgrade", &actions.ActionDescriptorOptions{ + // azd tool update [tool-name...] + group.Add("update", &actions.ActionDescriptorOptions{ Command: &cobra.Command{ - Use: "upgrade [tool-name...]", - Short: "Upgrade installed tools.", + Use: "update [tool-name...]", + Aliases: []string{"upgrade"}, + Short: "Update installed tools.", }, OutputFormats: []output.Format{output.JsonFormat, output.NoneFormat}, DefaultFormat: output.NoneFormat, @@ -155,7 +156,7 @@ func toolActions(root *actions.ActionDescriptor) *actions.ActionDescriptor { group.Add("check", &actions.ActionDescriptorOptions{ Command: &cobra.Command{ Use: "check", - Short: "Check for tool upgrades.", + Short: "Check for tool updates.", }, OutputFormats: []output.Format{output.JsonFormat, output.TableFormat}, DefaultFormat: output.TableFormat, @@ -1161,7 +1162,7 @@ func (a *toolInstallAction) resolveToolIds(ctx context.Context) ([]string, error } // --------------------------------------------------------------------------- -// azd tool upgrade [tool-name...] +// azd tool update [tool-name...] // --------------------------------------------------------------------------- type toolUpgradeFlags struct { @@ -1174,15 +1175,15 @@ func newToolUpgradeFlags(cmd *cobra.Command) *toolUpgradeFlags { flags := &toolUpgradeFlags{} cmd.Flags().BoolVar( &flags.all, "all", false, - "Upgrade all installed tools", + "Update all installed tools", ) cmd.Flags().BoolVar( &flags.dryRun, "dry-run", false, - "Preview what would be upgraded without making changes", + "Preview what would be updated without making changes", ) cmd.Flags().StringSliceVar( &flags.agents, "agent", nil, - "Upgrade the skill for the specified agent(s): copilot, claude. "+ + "Update the skill for the specified agent(s): copilot, claude. "+ "Use --agent all for every detected agent (skill tools only)", ) return flags @@ -1222,7 +1223,7 @@ func (a *toolUpgradeAction) Run(ctx context.Context) (*actions.ActionResult, err var toolsToUpgrade []*tool.ToolDefinition // fromVersions captures the pre-upgrade installed version per tool ID, - // populated on both branches so that tool.upgrade.from_version is + // populated on both branches so that tool.update.from_version is // emitted on the single-tool path regardless of whether the user // supplied explicit args. Detection failures are non-fatal here — // from_version is a best-effort telemetry signal, not a precondition @@ -1230,7 +1231,7 @@ func (a *toolUpgradeAction) Run(ctx context.Context) (*actions.ActionResult, err fromVersions := make(map[string]string) if len(a.args) > 0 && a.flags.all { - return nil, toolIDsWithAllError("upgrade") + return nil, toolIDsWithAllError("update") } switch { @@ -1278,7 +1279,7 @@ func (a *toolUpgradeAction) Run(ctx context.Context) (*actions.ActionResult, err // can't run (or would corrupt JSON), so require an explicit target // (tool IDs or --all) rather than implicitly upgrading every tool. if len(installed) > 0 && !promptAllowed(a.console, a.formatter) { - return nil, noToolTargetError("upgrade") + return nil, noToolTargetError("update") } chosen := installed if promptAllowed(a.console, a.formatter) && len(installed) > 0 { @@ -1302,7 +1303,7 @@ func (a *toolUpgradeAction) Run(ctx context.Context) (*actions.ActionResult, err return nil, a.formatter.Format([]*toolInstallResultItem{}, a.writer, nil) } a.console.Message(ctx, output.WithGrayFormat( - "No installed tools to upgrade.", + "No installed tools to update.", )) return nil, nil } @@ -1323,8 +1324,8 @@ func (a *toolUpgradeAction) Run(ctx context.Context) (*actions.ActionResult, err if a.formatter.Kind() != output.JsonFormat { a.console.MessageUxItem(ctx, &ux.MessageTitle{ - Title: "Upgrade Azure development tools (azd tool upgrade)", - TitleNote: "Upgrades installed tools to their latest versions", + Title: "Update Azure development tools (azd tool update)", + TitleNote: "Updates installed tools to their latest versions", }) } @@ -1358,7 +1359,7 @@ func (a *toolUpgradeAction) Run(ctx context.Context) (*actions.ActionResult, err operationFn := func(ctx context.Context, allIDs []string) ([]*tool.InstallResult, error) { return a.manager.UpgradeTools(ctx, allIDs, agentOpts...) } - outcome := runToolOperation(ctx, toolsToUpgrade, operationFn, "Upgrading", "upgrade", a.console, + outcome := runToolOperation(ctx, toolsToUpgrade, operationFn, "Updating", "update", a.console, a.formatter.Kind() == output.JsonFormat) upgradeResults = outcome.Items rawResults = outcome.Results @@ -1371,11 +1372,11 @@ func (a *toolUpgradeAction) Run(ctx context.Context) (*actions.ActionResult, err singleAttrs := singleResultCommonAttrs(r) if r.Tool != nil { if from, ok := fromVersions[r.Tool.Id]; ok && from != "" { - singleAttrs = append(singleAttrs, fields.ToolUpgradeFromVersionKey.String(from)) + singleAttrs = append(singleAttrs, fields.ToolUpdateFromVersionKey.String(from)) } } if r.Success && r.InstalledVersion != "" { - singleAttrs = append(singleAttrs, fields.ToolUpgradeToVersionKey.String(r.InstalledVersion)) + singleAttrs = append(singleAttrs, fields.ToolUpdateToVersionKey.String(r.InstalledVersion)) } tracing.SetUsageAttributes(singleAttrs...) } @@ -1414,25 +1415,25 @@ func (a *toolUpgradeAction) Run(ctx context.Context) (*actions.ActionResult, err } } - header := "Tool is upgraded." + header := "Tool is updated." if allUpToDate { header = "Tool is already up to date." } if len(rawResults) > 1 { - header = "Tools are upgraded." + header = "Tools are updated." if allUpToDate { header = "Tools are already up to date." } } // For a single tool, include the resulting version in the done message, - // e.g. "Tool is upgraded to v2.0.0." or + // e.g. "Tool is updated to v2.0.0." or // "Tool is already up to date (v1.1.75).". if len(rawResults) == 1 && rawResults[0].InstalledVersion != "" { version := rawResults[0].InstalledVersion if allUpToDate { header = fmt.Sprintf("Tool is already up to date (v%s).", version) } else { - header = fmt.Sprintf("Tool is upgraded to v%s.", version) + header = fmt.Sprintf("Tool is updated to v%s.", version) } } @@ -1472,7 +1473,7 @@ func (a *toolUpgradeAction) promptForUpgradeTools( multiSelect := uxlib.NewMultiSelect(&uxlib.MultiSelectOptions{ Writer: a.console.Handles().Stdout, Reader: a.console.Handles().Stdin, - Message: "Select tools to upgrade", + Message: "Select tools to update", Choices: choices, }) @@ -1518,7 +1519,7 @@ func (a *toolUpgradeAction) resolveAgentOptions( } // dryRun detects the current status of the tools and displays what -// the upgrade command would do without making changes. +// the update command would do without making changes. func (a *toolUpgradeAction) dryRun( ctx context.Context, tools []*tool.ToolDefinition, @@ -1533,7 +1534,7 @@ func (a *toolUpgradeAction) dryRun( ) } - action := "upgrade" + action := "update" currentVersion := "" if status.Installed { currentVersion = status.InstalledVersion @@ -1925,7 +1926,7 @@ func (a *toolCheckAction) Run(ctx context.Context) (*actions.ActionResult, error var results []*tool.UpdateCheckResult if a.formatter.Kind() != output.JsonFormat { spinner := uxlib.NewSpinner(&uxlib.SpinnerOptions{ - Text: "Checking for upgrades...", + Text: "Checking for updates...", ClearOnStop: true, Writer: a.writer, }) @@ -1934,13 +1935,13 @@ func (a *toolCheckAction) Run(ctx context.Context) (*actions.ActionResult, error results, detectErr = a.manager.CheckForUpdates(ctx) return detectErr }); err != nil { - return nil, fmt.Errorf("checking for upgrades: %w", err) + return nil, fmt.Errorf("checking for updates: %w", err) } } else { var err error results, err = a.manager.CheckForUpdates(ctx) if err != nil { - return nil, fmt.Errorf("checking for upgrades: %w", err) + return nil, fmt.Errorf("checking for updates: %w", err) } } @@ -2049,12 +2050,12 @@ func (a *toolCheckAction) Run(ctx context.Context) (*actions.ActionResult, error if hasUpdates { a.console.Message(ctx, "") a.console.Message(ctx, fmt.Sprintf( - "To upgrade: %s", - output.WithHighLightFormat("azd tool upgrade "), + "To update: %s", + output.WithHighLightFormat("azd tool update "), )) a.console.Message(ctx, fmt.Sprintf( - "To upgrade all: %s", - output.WithHighLightFormat("azd tool upgrade --all"), + "To update all: %s", + output.WithHighLightFormat("azd tool update --all"), )) } } @@ -2355,8 +2356,8 @@ type toolOpOutcome struct { // Parameters: // - tools: the resolved ToolDefinition slice to operate on // - operationFn: either InstallTools or UpgradeTools -// - title: verb for task titles (e.g. "Installing", "Upgrading") -// - action: action label for result items (e.g. "install", "upgrade") +// - title: verb for task titles (e.g. "Installing", "Updating") +// - action: action label for result items (e.g. "install", "update") // - console: for displaying warnings on partial failure // - quiet: when true (JSON output) the per-tool TaskList is routed to // io.Discard so its progress/control bytes never corrupt the @@ -2516,7 +2517,7 @@ func runToolOperation( taskErr := taskList.Run() if taskErr != nil && !quiet { // Build the past participle: "install" -> "installed", - // "upgrade" -> "upgraded". Appending only "d" would be wrong, + // "update" -> "updated". Appending only "d" would be wrong, // so append "ed" unless the verb already ends in "e". participle := action + "ed" if strings.HasSuffix(action, "e") { diff --git a/cli/azd/cmd/tool_test.go b/cli/azd/cmd/tool_test.go index fd579b40f12..e49ae2b471d 100644 --- a/cli/azd/cmd/tool_test.go +++ b/cli/azd/cmd/tool_test.go @@ -750,9 +750,9 @@ func TestToolInstallAction_Failure_ReturnsErrorNotSuccess(t *testing.T) { // TestToolUpgradeAction_SuccessEmitsFromAndToVersion exercises the upgrade // path end-to-end and verifies: -// - tool.upgrade.from_version is emitted from DetectTool (H2: no UX change, +// - tool.update.from_version is emitted from DetectTool (H2: no UX change, // reuses the existing detector) -// - tool.upgrade.to_version is emitted only on Success and reflects the +// - tool.update.to_version is emitted only on Success and reflects the // installer's InstalledVersion (H3) // - tool.id is emitted (single-tool, not tool.ids) func TestToolUpgradeAction_SuccessEmitsFromAndToVersion(t *testing.T) { @@ -795,17 +795,17 @@ func TestToolUpgradeAction_SuccessEmitsFromAndToVersion(t *testing.T) { require.True(t, ok) assert.Equal(t, "az-cli", gotID) - gotFrom, ok := lookupToolStrUsage(string(fields.ToolUpgradeFromVersionKey.Key)) - require.True(t, ok, "tool.upgrade.from_version must be emitted from detector output") + gotFrom, ok := lookupToolStrUsage(string(fields.ToolUpdateFromVersionKey.Key)) + require.True(t, ok, "tool.update.from_version must be emitted from detector output") assert.Equal(t, "1.0.0", gotFrom) - gotTo, ok := lookupToolStrUsage(string(fields.ToolUpgradeToVersionKey.Key)) - require.True(t, ok, "tool.upgrade.to_version must be emitted on success") + gotTo, ok := lookupToolStrUsage(string(fields.ToolUpdateToVersionKey.Key)) + require.True(t, ok, "tool.update.to_version must be emitted on success") assert.Equal(t, "2.0.0", gotTo) } // TestToolUpgradeAction_FailureDoesNotEmitToVersion verifies the H3 contract: -// when the upgrade fails, tool.upgrade.to_version is NOT emitted (since there +// when the update fails, tool.update.to_version is NOT emitted (since there // is no successfully-installed version to report). func TestToolUpgradeAction_FailureDoesNotEmitToVersion(t *testing.T) { tracing.ResetUsageAttributesForTest() @@ -842,13 +842,13 @@ func TestToolUpgradeAction_FailureDoesNotEmitToVersion(t *testing.T) { _, _ = action.Run(t.Context()) // from_version still emits (detected before the failed upgrade). - gotFrom, ok := lookupToolStrUsage(string(fields.ToolUpgradeFromVersionKey.Key)) + gotFrom, ok := lookupToolStrUsage(string(fields.ToolUpdateFromVersionKey.Key)) require.True(t, ok) assert.Equal(t, "1.0.0", gotFrom) // to_version must be absent — there is no installed version to report. - _, ok = lookupToolStrUsage(string(fields.ToolUpgradeToVersionKey.Key)) - assert.False(t, ok, "tool.upgrade.to_version must not be emitted on upgrade failure") + _, ok = lookupToolStrUsage(string(fields.ToolUpdateToVersionKey.Key)) + assert.False(t, ok, "tool.update.to_version must not be emitted on update failure") } // --------------------------------------------------------------------------- @@ -1351,7 +1351,7 @@ func TestToolUninstallAction_DryRun_DoesNotDelegate(t *testing.T) { } // TestToolUpgradeAction_All_UpgradesInstalledTools verifies that -// `azd tool upgrade --all` upgrades every installed tool (and only those), +// `azd tool update --all` updates every installed tool (and only those), // without an interactive selection prompt. func TestToolUpgradeAction_All_UpgradesInstalledTools(t *testing.T) { tracing.ResetUsageAttributesForTest() @@ -1403,7 +1403,7 @@ func TestToolUpgradeAction_All_UpgradesInstalledTools(t *testing.T) { } // TestToolUpgradeAction_All_JsonFormat_EmitsCleanJson exercises the reviewer's -// exact trigger — `azd tool upgrade --all --output json` — and verifies the +// exact trigger — `azd tool update --all --output json` — and verifies the // writer receives valid JSON. In JSON mode the detection spinner is // bypassed (detectAllTools) so no control bytes can corrupt the stream. func TestToolUpgradeAction_All_JsonFormat_EmitsCleanJson(t *testing.T) { @@ -1440,12 +1440,13 @@ func TestToolUpgradeAction_All_JsonFormat_EmitsCleanJson(t *testing.T) { var items []toolInstallResultItem require.NoError(t, json.Unmarshal(buf.Bytes(), &items), - "upgrade --all --output json must emit valid JSON") + "update --all --output json must emit valid JSON") require.NotEmpty(t, items, "at least one installed tool must be reported") + require.Equal(t, "update", items[0].Action) } // TestToolUpgradeAction_All_JsonFormat_EmptyEmitsArray verifies that when there -// is nothing to upgrade, `azd tool upgrade --all --output json` still emits an +// is nothing to update, `azd tool update --all --output json` still emits an // empty result array ([]) rather than a consoleMessage object, so automation // sees one stable shape. func TestToolUpgradeAction_All_JsonFormat_EmptyEmitsArray(t *testing.T) { @@ -1484,7 +1485,7 @@ func TestToolUpgradeAction_All_JsonFormat_EmptyEmitsArray(t *testing.T) { assert.Empty(t, items) } -// TestToolUpgradeAction_IDsWithAll_Errors verifies that `azd tool upgrade foo +// TestToolUpgradeAction_IDsWithAll_Errors verifies that `azd tool update foo // --all` is rejected rather than silently ignoring foo and upgrading everything. func TestToolUpgradeAction_IDsWithAll_Errors(t *testing.T) { tracing.ResetUsageAttributesForTest() @@ -1514,7 +1515,7 @@ func TestToolUpgradeAction_IDsWithAll_Errors(t *testing.T) { } // TestToolUpgradeAction_NoPrompt_WithoutTarget_Errors verifies that -// `azd tool upgrade` with --no-prompt (or a non-interactive terminal) and no +// `azd tool update` with --no-prompt (or a non-interactive terminal) and no // tool IDs and no --all fails with guidance instead of implicitly upgrading // every installed tool — consistent with install/uninstall and azd's // --no-prompt contract. @@ -1555,7 +1556,7 @@ func TestToolUpgradeAction_NoPrompt_WithoutTarget_Errors(t *testing.T) { } // TestToolUpgradeAction_JsonOnTTY_WithoutTarget_Errors verifies that -// `azd tool upgrade --output json` on an interactive terminal (no --no-prompt) +// `azd tool update --output json` on an interactive terminal (no --no-prompt) // requires an explicit target rather than opening the no-argument picker, whose // output would corrupt the JSON result written to the same stdout. func TestToolUpgradeAction_JsonOnTTY_WithoutTarget_Errors(t *testing.T) { @@ -1705,7 +1706,7 @@ func TestToolUpgradeAction_ChangedVersion_ReportsUpgraded(t *testing.T) { require.NoError(t, err) require.NotNil(t, result) require.NotNil(t, result.Message) - assert.Equal(t, "Tool is upgraded to v2.0.0.", result.Message.Header) + assert.Equal(t, "Tool is updated to v2.0.0.", result.Message.Header) } // TestSkillAgentDisplayName verifies an installed agent's command identity is @@ -2004,7 +2005,7 @@ func TestToolUpgradeAction_MultiAgentSkill_UpgradedNotUpToDate(t *testing.T) { require.NoError(t, err) require.NotNil(t, result) require.NotNil(t, result.Message) - assert.Equal(t, "Tool is upgraded to v1.1.87.", result.Message.Header, + assert.Equal(t, "Tool is updated to v1.1.87.", result.Message.Header, "a multi-agent skill with an upgraded agent must not read as already up to date") } diff --git a/cli/azd/docs/extensions/extension-framework.md b/cli/azd/docs/extensions/extension-framework.md index 60f550d995f..06867524084 100644 --- a/cli/azd/docs/extensions/extension-framework.md +++ b/cli/azd/docs/extensions/extension-framework.md @@ -148,14 +148,16 @@ Uninstalls one or more previously installed extensions. - `--all` Removes all installed extensions when specified. -#### `azd extension upgrade ` +#### `azd extension update ` -Upgrades one or more extensions to the latest versions. +> Aliased as `azd extension upgrade` for backward compatibility. -- `--all` Upgrades all previously installed extensions when specified. -- `-v, --version` Upgrades a specified extension to an exact version, if provided. -- `-s, --source` Specifies the source used for the upgrade. In addition to registered source names, this accepts a registry location (URL or file path). `azd` registers the location as a source before resolving the extension, updates the extension's stored source after a successful upgrade, and rejects locations under `--no-prompt`; add the source first with `azd extension source add`. -- `--no-dependency-upgrades` Skips upgrading dependencies declared by extension packs. +Updates one or more extensions to the latest versions. + +- `--all` Updates all previously installed extensions when specified. +- `-v, --version` Updates a specified extension to an exact version, if provided. +- `-s, --source` Specifies the source used for the update. In addition to registered source names, this accepts a registry location (URL or file path). `azd` registers the location as a source before resolving the extension, updates the extension's stored source after a successful update, and rejects locations under `--no-prompt`; add the source first with `azd extension source add`. +- `--no-dependency-upgrades` Skips updating dependencies declared by extension packs. ## Developing Extensions @@ -1209,9 +1211,9 @@ dependencies: version: "~0.1.0-preview" ``` -Pack manifests must include at least one dependency. They may omit `capabilities`, `namespace`, `entryPoint`, `usage`, and `examples` when the pack has no commands of its own. Installing a pack installs its dependencies recursively from the same extension source as the pack. Dependency versions in the manifest support semver constraints, but command-line `--version` values for `azd extension install` and `azd extension upgrade` are exact versions. +Pack manifests must include at least one dependency. They may omit `capabilities`, `namespace`, `entryPoint`, `usage`, and `examples` when the pack has no commands of its own. Installing a pack installs its dependencies recursively from the same extension source as the pack. Dependency versions in the manifest support semver constraints, but command-line `--version` values for `azd extension install` and `azd extension update` are exact versions. -Upgrading a pack upgrades the pack and, by default, reconciles installed dependencies to the highest published versions that satisfy the pack's declared dependency constraints. This dependency reconciliation still runs when the pack itself is already current, because an unchanged pack can point to a dependency range with newer matching versions. Users can disable automatic dependency upgrades with `azd extension upgrade --no-dependency-upgrades`. +Updating a pack updates the pack and, by default, reconciles installed dependencies to the highest published versions that satisfy the pack's declared dependency constraints. This dependency reconciliation still runs when the pack itself is already current, because an unchanged pack can point to a dependency range with newer matching versions. Users can disable automatic dependency updates with `azd extension update --no-dependency-upgrades`. #### Provider Registration @@ -3243,19 +3245,19 @@ Registry schema versions use `major.minor` format (e.g. `"1.0"`, `"1.1"`, `"2.0" |----------|----------| | Missing `schemaVersion` | Treated as `"1.0"` for backward compatibility | | Same major, newer minor (e.g. `"1.1"`) | Accepted silently — minor bumps are backward compatible | -| Newer major (e.g. `"2.0"`) | Rejected with an error and upgrade guidance | +| Newer major (e.g. `"2.0"`) | Rejected with an error and update guidance | | `0.x` (e.g. `"0.1"`) | Accepted — pre-release schema versions are valid | | Malformed version string | Rejected with a descriptive parse error | -### Upgrade Guidance +### Update Guidance When azd encounters a registry with a schema version it cannot support, it will -display an error with a suggestion to upgrade: +display an error with a suggestion to update: ``` ERROR: registry schema version 2.0 is not supported (max supported: 1.0) -Suggestion: Upgrade azd to the latest version to use this registry +Suggestion: Update azd to the latest version to use this registry https://aka.ms/azd/install ``` diff --git a/cli/azd/docs/extensions/extension-resolution-and-versioning.md b/cli/azd/docs/extensions/extension-resolution-and-versioning.md index 0cd889cd877..6908611bffc 100644 --- a/cli/azd/docs/extensions/extension-resolution-and-versioning.md +++ b/cli/azd/docs/extensions/extension-resolution-and-versioning.md @@ -13,7 +13,7 @@ Extension sources are manifests that describe the extensions available for insta | `url` | HTTP/HTTPS endpoint | Remote JSON manifest fetched over the network. | | `file` | Local filesystem path | Local JSON file, useful for development and offline scenarios. | -In addition, extensions installed from a [self-contained bundle](#self-contained-bundles) are tagged with a reserved `bundle` source. `bundle` is not a configurable source type and never appears in `azd extension source list` — it simply marks an extension that has no live registry to track updates against. Such extensions are listed with their `bundle` source in `azd extension list` and are skipped by `azd extension upgrade`. The name `bundle` is reserved, so it cannot be used as a user-configured source name. +In addition, extensions installed from a [self-contained bundle](#self-contained-bundles) are tagged with a reserved `bundle` source. `bundle` is not a configurable source type and never appears in `azd extension source list` — it simply marks an extension that has no live registry to track updates against. Such extensions are listed with their `bundle` source in `azd extension list` and are skipped by `azd extension update`. The name `bundle` is reserved, so it cannot be used as a user-configured source name. Sources are configured in `~/.azd/config.json`. You can manage them with the following commands: @@ -139,8 +139,8 @@ When `azd` resolves versions, it filters them into compatible and incompatible s ### Behavior - `azd` filters out all versions whose `requiredAzdVersion` constraint is not satisfied by the running `azd` version, then selects the **highest remaining compatible version** that also matches the user's version constraint. -- If a **newer incompatible version** exists beyond the selected version, `azd` shows a **warning** suggesting the user upgrade `azd`. -- If **no compatible versions** remain after filtering, the install **fails** with guidance to upgrade `azd`. The install also fails if the user explicitly requests a specific version that is incompatible. +- If a **newer incompatible version** exists beyond the selected version, `azd` shows a **warning** suggesting the user update `azd`. +- If **no compatible versions** remain after filtering, the install **fails** with guidance to update `azd`. The install also fails if the user explicitly requests a specific version that is incompatible. - If `requiredAzdVersion` is **empty or cannot be parsed**, the version is treated as compatible (fail-open). This ensures that extensions without the field remain installable. ## Install Flow @@ -166,10 +166,10 @@ Once a version is resolved, installation proceeds through these steps: When the source is **not** changing (same source as the installed extension): - **Same version** — a no-op; the install is skipped. -- **Newer version** — upgraded in place. +- **Newer version** — updated in place. - **Older version** — a downgrade; `azd` **prompts for confirmation** before replacing the newer install with an older one. Declining skips the install. In `--no-prompt` mode `azd` skips with guidance to pass `--force`, and `--force` proceeds without prompting. -When the source **is** changing (for example installing a bundle build over a registry build, or vice versa), the artifacts may differ, so `azd` does not silently proceed, no-op, or block a downgrade. Instead it **prompts for confirmation** before replacing the installed extension. The prompt states the version transition explicitly — *Reinstall*, *Upgrade to ``*, or *Downgrade to ``* — and the target source. Declining skips the install; confirming reinstalls and re-points the extension to the new source. In `--no-prompt` mode `azd` skips with guidance to pass `--force`, and `--force` proceeds without prompting. +When the source **is** changing (for example installing a bundle build over a registry build, or vice versa), the artifacts may differ, so `azd` does not silently proceed, no-op, or block a downgrade. Instead it **prompts for confirmation** before replacing the installed extension. The prompt states the version transition explicitly — *Reinstall*, *Update to ``*, or *Downgrade to ``* — and the target source. Declining skips the install; confirming reinstalls and re-points the extension to the new source. In `--no-prompt` mode `azd` skips with guidance to pass `--force`, and `--force` proceeds without prompting. Because each bundle install registers a unique transient source, installing from **any** bundle over an already-installed extension is always treated as a source change — so it prompts even when the bundled version matches the installed one (the two builds may not be byte-identical). @@ -209,7 +209,7 @@ The install flow treats the bundle as an **installer, not a registry** — nothi Because a bundle does not register a lasting source, a bundle-installed extension is tracked under the reserved `bundle` source: - `azd extension list` shows it with its `bundle` source and a normal `✓ Up to date` status. It has no "latest" version to compare against, so no update is ever reported. -- `azd extension upgrade` skips bundle-installed extensions with a note that they were installed from a self-contained bundle. +- `azd extension update` skips bundle-installed extensions with a note that they were installed from a self-contained bundle. - `azd extension source list` does **not** show an entry for the bundle — there is no leftover source to clean up. To update a bundle-installed extension, install a newer bundle: @@ -482,9 +482,9 @@ azd extension install my.experimental.extension --version 2.0.0-beta.1 --source If an extension exists in both the `azd` and `dev` sources and you do not specify `--source`, `azd` will prompt you to choose (in interactive mode) or return an error (in non-interactive mode). See [Handle Conflicts](#3-handle-conflicts) for details. -### Upgrade and Dev→Main Promotion +### Update and Dev→Main Promotion -When you run `azd extension upgrade`, extensions installed from the dev registry are evaluated for **one-way promotion** to the main registry. Promotion occurs automatically when: +When you run `azd extension update`, extensions installed from the dev registry are evaluated for **one-way promotion** to the main registry. Promotion occurs automatically when: 1. **The extension is no longer in the dev registry** — it was removed from `registry.dev.json` after being promoted to `registry.json`. 2. **The main registry has a newer version** — the latest version in the main registry is strictly greater than the latest version in the dev registry. @@ -494,13 +494,13 @@ When promotion happens, the extension's stored source switches from `dev` to `az > [!NOTE] > If the main and dev registries have the **same** latest version, the extension stays on its current (dev) source. Equal versions are source-sticky. -The upgrade priority chain is: +The update priority chain is: 1. **Explicit `--source` flag** — always wins if provided 2. **Stored source** — the source the extension was originally installed from 3. **Main registry fallback** — `azd` checks the main registry for promotion opportunities -Promotion events are tracked via `ext.promote` telemetry. Upgrade events (regardless of promotion) are tracked via `ext.upgrade`. +Promotion events are tracked via `ext.promote` telemetry. Update events (regardless of promotion) are tracked via `ext.update`. #### Example: Dev→Main Promotion in Action @@ -509,9 +509,9 @@ Promotion events are tracked via `ext.promote` telemetry. Upgrade events (regard azd extension install my.extension --source dev # Later, the extension graduates to the main registry with a newer version. -# Running upgrade will auto-promote: -azd extension upgrade my.extension -# Output: my.extension upgraded from 1.0.0-beta.2 (dev) → 1.0.0 (azd) +# Running update will auto-promote: +azd extension update my.extension +# Output: my.extension updated from 1.0.0-beta.2 (dev) → 1.0.0 (azd) ``` ### Submitting an Extension to the Dev Registry @@ -610,7 +610,7 @@ When the same extension ID is present in both `azd` and `dev`: #### Source ordering affects resolution -Sources are sorted **alphabetically by name**. With the default naming (`azd` and `dev`), `azd` is consulted first because `"azd"` sorts before `"dev"`. If you name your dev source `"aaa-dev"`, it would be consulted first. The name only affects the order in which sources are searched — it does not affect upgrade or promotion behavior. +Sources are sorted **alphabetically by name**. With the default naming (`azd` and `dev`), `azd` is consulted first because `"azd"` sorts before `"dev"`. If you name your dev source `"aaa-dev"`, it would be consulted first. The name only affects the order in which sources are searched — it does not affect update or promotion behavior. #### Stale cache after registry updates @@ -681,12 +681,12 @@ To remove the nightly registry later: azd extension source remove nightly ``` -### Upgrade and Nightly→Main Promotion +### Update and Nightly→Main Promotion -Nightly versions use semver prerelease labels, so the standard `azd extension upgrade` flow works: +Nightly versions use semver prerelease labels, so the standard `azd extension update` flow works: -- A newer nightly (higher build id, or a higher base version) supersedes an older one, so `azd extension upgrade` pulls the latest nightly. -- When the extension ships a **stable** release whose base version matches your nightly (for example stable `1.2.3` versus `1.2.3-nightly.200`), the stable release outranks the nightly and you are **automatically promoted** to the `azd` registry on your next upgrade. +- A newer nightly (higher build id, or a higher base version) supersedes an older one, so `azd extension update` pulls the latest nightly. +- When the extension ships a **stable** release whose base version matches your nightly (for example stable `1.2.3` versus `1.2.3-nightly.200`), the stable release outranks the nightly and you are **automatically promoted** to the `azd` registry on your next update. > [!NOTE] > If your nightly was built from a **prerelease** base (for example `1.2.3-preview.nightly.60`), it sorts **above** the matching stable prerelease `1.2.3-preview`. In that case you are not promoted until the stable registry advances to a higher base version. This is expected semver precedence behavior. diff --git a/cli/azd/docs/style-guidelines/responsive-layout-style-guide.md b/cli/azd/docs/style-guidelines/responsive-layout-style-guide.md index f4c21253ffb..26a87bedbcd 100644 --- a/cli/azd/docs/style-guidelines/responsive-layout-style-guide.md +++ b/cli/azd/docs/style-guidelines/responsive-layout-style-guide.md @@ -51,7 +51,7 @@ Each column is a `PrettyColumn` (a `Column` plus responsive metadata). Use the c | Status text | Meaning | Color helper | | --- | --- | --- | | `Installed` / `Up to date` | Present and current | `WithSuccessFormat` | -| `Upgrade available` | Installed but outdated | `WithWarningFormat` | +| `Update available` | Installed but outdated | `WithWarningFormat` | | `Not installed` | Absent (not an error) | `WithGrayFormat` | ## Layout Examples diff --git a/cli/azd/docs/tracing-in-azd.md b/cli/azd/docs/tracing-in-azd.md index f3dde61f29a..33c895630c3 100644 --- a/cli/azd/docs/tracing-in-azd.md +++ b/cli/azd/docs/tracing-in-azd.md @@ -82,7 +82,7 @@ adding new events for extension and hook lifecycle telemetry. | ----- | --------- | -------------------- | ---------- | | `ext.run` | Running an installed extension command through `azd`. | Command attributes such as `cmd.entry`, `cmd.flags`, `cmd.args.count`, plus `extension.installed` on the root span. | `name=ext.run`, `cmd.entry=cmd.ai.chat`, `cmd.flags=["model"]`, `cmd.args.count=0` | | `ext.install` | Installing one extension version. | `extension.id` (set as soon as installation begins); `extension.version` (set after the version is resolved). On failure the span uses OpenTelemetry status `Error`; `EndWithStatus` derives the status description from the error type. | `name=ext.install`, `extension.id=microsoft.azd.ai`, `extension.version=1.2.0`, `status=Ok` | -| `ext.upgrade` | Upgrading one extension attempt. | `extension.id`, `extension.version.from`, `extension.version.to`, `extension.source`, `extension.upgrade.duration_ms`, `extension.upgrade.outcome`. | `name=ext.upgrade`, `extension.id=microsoft.azd.ai`, `extension.version.from=1.1.0`, `extension.version.to=1.2.0`, `extension.upgrade.outcome=upgraded` | +| `ext.update` | Updating one extension attempt. | `extension.id`, `extension.version.from`, `extension.version.to`, `extension.source`, `extension.update.duration_ms`, `extension.update.outcome`. | `name=ext.update`, `extension.id=microsoft.azd.ai`, `extension.version.from=1.1.0`, `extension.version.to=1.2.0`, `extension.update.outcome=upgraded` | | `ext.promote` | Promoting an extension registry entry, such as dev to main. | `extension.id`, `extension.version.from`, `extension.version.to`, `extension.source.from`, `extension.source.to`. | `name=ext.promote`, `extension.id=microsoft.azd.ai`, `extension.source.from=dev`, `extension.source.to=main`, `status=Ok` | | `hooks.exec` | Executing a project, layer, or service lifecycle hook. | `hooks.name`, `hooks.type`, `hooks.kind`; status description uses hook-specific codes such as `hook.validation_failed`. | `name=hooks.exec`, `hooks.name=predeploy`, `hooks.type=service`, `hooks.kind=sh`, `status=Ok` | @@ -95,13 +95,13 @@ Extension telemetry attributes are defined in [`fields.go`](../internal/tracing/ | `extension.id` | Extension identifier. | `microsoft.azd.ai` | | `extension.version` | Installed extension version. | `1.2.0` | | `extension.installed` | Installed extensions on a command span, each formatted as `id@version`. | `["microsoft.azd.ai@1.2.0"]` | -| `extension.version.from` | Version before an upgrade or promotion. | `1.1.0` | -| `extension.version.to` | Version after an upgrade or promotion. | `1.2.0` | -| `extension.source` | Registry source used for an upgrade. | `main` | +| `extension.version.from` | Version before an update or promotion. | `1.1.0` | +| `extension.version.to` | Version after an update or promotion. | `1.2.0` | +| `extension.source` | Registry source used for an update. | `main` | | `extension.source.from` | Registry source before a promotion. | `dev` | | `extension.source.to` | Registry source after a promotion. | `main` | -| `extension.upgrade.duration_ms` | Upgrade duration in milliseconds. | `1532` | -| `extension.upgrade.outcome` | Upgrade result status. | `upgraded` | +| `extension.update.duration_ms` | Update duration in milliseconds. | `1532` | +| `extension.update.outcome` | Update result status. | `upgraded` | ### Hook Attributes @@ -207,7 +207,7 @@ These example PRs include adding both new spans and events and can be used as re ## Tool Command Telemetry -The `azd tool` command group emits telemetry that captures **per-operation outcomes** for install, upgrade, check, and show. The first-run telemetry contract remains defined for a possible future experience but is not currently emitted. All active attributes are attached as **usage attributes** via `tracing.SetUsageAttributes`, which means they appear on the user's actual command span (e.g. `cmd.tool.install`) rather than on a separate child span. +The `azd tool` command group emits telemetry that captures **per-operation outcomes** for install, update, check, and show. The first-run telemetry contract remains defined for a possible future experience but is not currently emitted. All active attributes are attached as **usage attributes** via `tracing.SetUsageAttributes`, which means they appear on the user's actual command span (e.g. `cmd.tool.install`) rather than on a separate child span. ### Dormant First-Run Experience @@ -230,21 +230,21 @@ The first-run middleware (`cmd/middleware/tool_first_run.go`) is not registered ### Per-Operation Attributes -The `tool install` / `tool upgrade` / `tool check` / `tool show` actions emit: +The `tool install` / `tool update` / `tool check` / `tool show` actions emit: | Attribute | Type | Emitted by | Notes | | --- | --- | --- | --- | -| `tool.id` | string | Single-target install / upgrade / show (`len(ids) == 1`) | The built-in tool identifier. Mutually exclusive with `tool.ids`. | -| `tool.ids` | string | Multi-target batch install / upgrade (`len(ids) > 1`) | Comma-separated **sorted** built-in tool IDs. Mutually exclusive with `tool.id` — single-tool operations emit only `tool.id`. Sorting keeps attribute cardinality bounded (set vs permutation). | -| `tool.dry_run` | bool | install / upgrade | Reflects the `--dry-run` flag. | -| `tool.install.strategy` | string | Single-target install / upgrade | E.g. `winget`, `brew`, `manual`. | -| `tool.install.success` | bool | Single-target install / upgrade | Whether the per-tool operation succeeded. | -| `tool.install.success_count` | int | Batch install / upgrade | Number of tools that succeeded. | -| `tool.install.failure_count` | int | Batch install / upgrade | Number of tools that failed. | +| `tool.id` | string | Single-target install / update / show (`len(ids) == 1`) | The built-in tool identifier. Mutually exclusive with `tool.ids`. | +| `tool.ids` | string | Multi-target batch install / update (`len(ids) > 1`) | Comma-separated **sorted** built-in tool IDs. Mutually exclusive with `tool.id` — single-tool operations emit only `tool.id`. Sorting keeps attribute cardinality bounded (set vs permutation). | +| `tool.dry_run` | bool | install / update | Reflects the `--dry-run` flag. | +| `tool.install.strategy` | string | Single-target install / update | E.g. `winget`, `brew`, `manual`. | +| `tool.install.success` | bool | Single-target install / update | Whether the per-tool operation succeeded. | +| `tool.install.success_count` | int | Batch install / update | Number of tools that succeeded. | +| `tool.install.failure_count` | int | Batch install / update | Number of tools that failed. | | `tool.install.failed_ids` | string | At least one failure | Comma-separated **sorted** tool IDs whose operation failed. **Only tool IDs are recorded — error messages flow through the global error middleware (`error.message`).** When the batch call itself errors before any per-tool result is produced, the count of failed IDs may be **less than `failure_count`** (failures are synthesized from the requested set, but a synthesized entry with no `Tool` reference is omitted from the ID list to avoid emitting "unknown"). | -| `tool.install.duration_ms` | int | Batch install / upgrade | Wall-clock duration of the operation in milliseconds. Per-tool durations are intentionally **not** emitted: the cardinality cost would be `O(tools × installs)` for limited diagnostic value, and the aggregate captures the only number actionable at fleet scale. Per-tool durations remain available in the in-process `InstallResult.Duration` for local logging / dry-run reporting. | -| `tool.upgrade.from_version` | string | Single-target upgrade | Pre-upgrade installed version. Captured via detection on both the explicit-args (`azd tool upgrade `) and auto-detect (`azd tool upgrade`) paths. Unset only when detection failed or the tool was not previously installed. | -| `tool.upgrade.to_version` | string | Single-target upgrade succeeded | Post-upgrade installed version. Only emitted when the upgrade succeeded — on failure `InstalledVersion` is either the unchanged pre-upgrade value or empty, which would be ambiguous against `from_version`. | +| `tool.install.duration_ms` | int | Batch install / update | Wall-clock duration of the operation in milliseconds. Per-tool durations are intentionally **not** emitted: the cardinality cost would be `O(tools × installs)` for limited diagnostic value, and the aggregate captures the only number actionable at fleet scale. Per-tool durations remain available in the in-process `InstallResult.Duration` for local logging / dry-run reporting. | +| `tool.update.from_version` | string | Single-target update | Pre-update installed version. Captured via detection on both the explicit-args (`azd tool update `) and auto-detect (`azd tool update`) paths. Unset only when detection failed or the tool was not previously installed. | +| `tool.update.to_version` | string | Single-target update succeeded | Post-update installed version. Only emitted when the update succeeded — on failure `InstalledVersion` is either the unchanged pre-update value or empty, which would be ambiguous against `from_version`. | | `tool.check.updates_available` | int | `tool check` | Count of tools whose `UpdateAvailable` is `true`. | > **PII rule:** Never include free-form error strings, file paths, or user input in tool telemetry. Stick to built-in tool IDs and semver-style version strings. Error messages are already captured by the global error middleware on the same span. diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_local.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_local.go index 05f10440b32..320a6cc2569 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_local.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_local.go @@ -234,7 +234,7 @@ func newCheckGRPCAndVersion(deps Dependencies) Check { Message: fmt.Sprintf( "Extension version %s is older than %s; the new hosted-agents backend requires the floor.", ver, MinNewBackendVersion), - Suggestion: "Upgrade with `azd ext upgrade azure.ai.agents`.", + Suggestion: "Update with `azd ext update azure.ai.agents`.", Links: []string{"https://aka.ms/hostedagents/tsg/readme"}, Details: map[string]any{ "extensionVersion": ver, diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_local_test.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_local_test.go index 3a05a0bf529..f770df2a2d2 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_local_test.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/doctor/checks_local_test.go @@ -165,7 +165,7 @@ func TestCheckGRPCAndVersion_BelowFloor_Warns(t *testing.T) { require.Equal(t, StatusWarn, got.Status) require.Contains(t, got.Message, "0.1.26-preview") require.Contains(t, got.Message, MinNewBackendVersion) - require.Contains(t, got.Suggestion, "azd ext upgrade azure.ai.agents") + require.Contains(t, got.Suggestion, "azd ext update azure.ai.agents") require.Contains(t, got.Links, "https://aka.ms/hostedagents/tsg/readme") require.Equal(t, "0.1.26-preview", got.Details["extensionVersion"]) require.Equal(t, MinNewBackendVersion, got.Details["minBackendVersion"]) diff --git a/cli/azd/extensions/azure.ai.agents/internal/cmd/init.go b/cli/azd/extensions/azure.ai.agents/internal/cmd/init.go index 884ca71f428..bba06185dca 100644 --- a/cli/azd/extensions/azure.ai.agents/internal/cmd/init.go +++ b/cli/azd/extensions/azure.ai.agents/internal/cmd/init.go @@ -185,7 +185,7 @@ func checkAiModelServiceAvailable(ctx context.Context, azdClient *azdext.AzdClie return exterrors.Compatibility( exterrors.CodeIncompatibleAzdVersion, "this version of the azure.ai.agents extension is incompatible with your installed version of azd.", - "upgrade azd to the latest version (https://aka.ms/azd/upgrade) and retry", + "update azd to the latest version (https://aka.ms/azd/upgrade) and retry", ) } diff --git a/cli/azd/extensions/azure.coding-agent/README.md b/cli/azd/extensions/azure.coding-agent/README.md index 995f8c00026..80591d3f8d8 100644 --- a/cli/azd/extensions/azure.coding-agent/README.md +++ b/cli/azd/extensions/azure.coding-agent/README.md @@ -29,7 +29,7 @@ azd extension install azure.coding-agent Or, if you already the `azure.coding-agent` extension installed, and you want to upgrade to the latest version: ```shell -azd extension upgrade azure.coding-agent +azd extension update azure.coding-agent ``` ## Usage diff --git a/cli/azd/internal/figspec/customizations.go b/cli/azd/internal/figspec/customizations.go index 47917592b20..ec7816afd80 100644 --- a/cli/azd/internal/figspec/customizations.go +++ b/cli/azd/internal/figspec/customizations.go @@ -92,7 +92,7 @@ func (c *Customizations) GetCommandArgGenerator(ctx *CommandContext, argName str if argName == "extension-id" { return FigGenListExtensions } - case "azd extension upgrade", "azd extension uninstall": + case "azd extension update", "azd extension uninstall": if argName == "extension-id" { return FigGenListInstalledExtensions } diff --git a/cli/azd/internal/figspec/fig_generators_test.go b/cli/azd/internal/figspec/fig_generators_test.go index 75a58f094e4..517faab4798 100644 --- a/cli/azd/internal/figspec/fig_generators_test.go +++ b/cli/azd/internal/figspec/fig_generators_test.go @@ -28,7 +28,7 @@ func TestCustomizations_GetCommandArgGenerator(t *testing.T) { // install is handled via GetCommandArgs (combined id|zip arg), not here. {"ext_install", "azd extension install", "extension-id", ""}, {"ext_show", "azd extension show", "extension-id", FigGenListExtensions}, - {"ext_upgrade", "azd extension upgrade", "extension-id", FigGenListInstalledExtensions}, + {"ext_update", "azd extension update", "extension-id", FigGenListInstalledExtensions}, {"ext_uninstall", "azd extension uninstall", "extension-id", FigGenListInstalledExtensions}, {"config_get", "azd config get", "path", FigGenListConfigKeys}, {"config_set", "azd config set", "path", FigGenListConfigKeys}, diff --git a/cli/azd/internal/tracing/events/events.go b/cli/azd/internal/tracing/events/events.go index 5e89fb7cbf7..fa279a0cb30 100644 --- a/cli/azd/internal/tracing/events/events.go +++ b/cli/azd/internal/tracing/events/events.go @@ -28,8 +28,8 @@ const AgentTroubleshootEvent = "agent.troubleshoot" const ( ExtensionRunEvent = "ext.run" ExtensionInstallEvent = "ext.install" - // ExtensionUpgradeEvent tracks a single extension upgrade attempt. - ExtensionUpgradeEvent = "ext.upgrade" + // ExtensionUpdateEvent tracks a single extension update attempt. + ExtensionUpdateEvent = "ext.update" // ExtensionPromoteEvent tracks a registry promotion (e.g., dev → main). ExtensionPromoteEvent = "ext.promote" ) diff --git a/cli/azd/internal/tracing/fields/fields.go b/cli/azd/internal/tracing/fields/fields.go index f59a0bf8cd0..ff0064aa05b 100644 --- a/cli/azd/internal/tracing/fields/fields.go +++ b/cli/azd/internal/tracing/fields/fields.go @@ -525,7 +525,7 @@ var ( } // ToolDryRunKey records whether `--dry-run` was specified for an - // `azd tool install` or `azd tool upgrade` invocation. + // `azd tool install` or `azd tool update` invocation. ToolDryRunKey = AttributeKey{ Key: attribute.Key("tool.dry_run"), Classification: SystemMetadata, @@ -590,7 +590,7 @@ var ( // ToolFirstRunInstallSuccessCountKey mirrors ToolInstallSuccessCountKey // but is emitted only from the first-run middleware, so the user's - // subsequent `azd tool install` / `azd tool upgrade` command (which + // subsequent `azd tool install` / `azd tool update` command (which // emits its own `tool.install.success_count`) does not overwrite the // first-run signal on the same span. ToolFirstRunInstallSuccessCountKey = AttributeKey{ @@ -626,19 +626,19 @@ var ( IsMeasurement: true, } - // ToolUpgradeFromVersionKey records the previous version of a tool - // being upgraded (single-target upgrades only). - ToolUpgradeFromVersionKey = AttributeKey{ - Key: attribute.Key("tool.upgrade.from_version"), + // ToolUpdateFromVersionKey records the previous version of a tool + // being updated (single-target updates only). + ToolUpdateFromVersionKey = AttributeKey{ + Key: attribute.Key("tool.update.from_version"), Classification: SystemMetadata, Purpose: FeatureInsight, } - // ToolUpgradeToVersionKey records the new version after upgrade - // (single-target upgrades only). Emitted only when the upgrade + // ToolUpdateToVersionKey records the new version after update + // (single-target updates only). Emitted only when the update // succeeds. - ToolUpgradeToVersionKey = AttributeKey{ - Key: attribute.Key("tool.upgrade.to_version"), + ToolUpdateToVersionKey = AttributeKey{ + Key: attribute.Key("tool.update.to_version"), Classification: SystemMetadata, Purpose: FeatureInsight, } @@ -1160,19 +1160,19 @@ var ( Classification: SystemMetadata, Purpose: FeatureInsight, } - // ExtensionVersionFrom is the installed version before an upgrade. + // ExtensionVersionFrom is the installed version before an update. ExtensionVersionFrom = AttributeKey{ Key: attribute.Key("extension.version.from"), Classification: SystemMetadata, Purpose: FeatureInsight, } - // ExtensionVersionTo is the target version after an upgrade. + // ExtensionVersionTo is the target version after an update. ExtensionVersionTo = AttributeKey{ Key: attribute.Key("extension.version.to"), Classification: SystemMetadata, Purpose: FeatureInsight, } - // ExtensionSource is the registry source used for the upgrade. + // ExtensionSource is the registry source used for the update. ExtensionSource = AttributeKey{ Key: attribute.Key("extension.source"), Classification: SystemMetadata, @@ -1196,28 +1196,28 @@ var ( Classification: SystemMetadata, Purpose: FeatureInsight, } - // ExtensionUpgradeDurationMs is the time in milliseconds for one upgrade. - ExtensionUpgradeDurationMs = AttributeKey{ - Key: attribute.Key("extension.upgrade.duration_ms"), + // ExtensionUpdateDurationMs is the time in milliseconds for one update. + ExtensionUpdateDurationMs = AttributeKey{ + Key: attribute.Key("extension.update.duration_ms"), Classification: SystemMetadata, Purpose: PerformanceAndHealth, IsMeasurement: true, } - // ExtensionUpgradeOutcome is the upgrade result status. - ExtensionUpgradeOutcome = AttributeKey{ - Key: attribute.Key("extension.upgrade.outcome"), + // ExtensionUpdateOutcome is the update result status. + ExtensionUpdateOutcome = AttributeKey{ + Key: attribute.Key("extension.update.outcome"), Classification: SystemMetadata, Purpose: FeatureInsight, } - // ExtensionDependencyOf is the parent extension for a dependency upgrade. + // ExtensionDependencyOf is the parent extension for a dependency update. ExtensionDependencyOf = AttributeKey{ Key: attribute.Key("extension.dependency_of"), Classification: SystemMetadata, Purpose: FeatureInsight, } - // ExtensionDependencyUpgradeCount is the recursive dependency upgrade count. - ExtensionDependencyUpgradeCount = AttributeKey{ - Key: attribute.Key("extension.dependency_upgrade_count"), + // ExtensionDependencyUpdateCount is the recursive dependency update count. + ExtensionDependencyUpdateCount = AttributeKey{ + Key: attribute.Key("extension.dependency_update_count"), Classification: SystemMetadata, Purpose: FeatureInsight, IsMeasurement: true, diff --git a/cli/azd/pkg/extensions/manager.go b/cli/azd/pkg/extensions/manager.go index eae56416dda..1798d8d9ad2 100644 --- a/cli/azd/pkg/extensions/manager.go +++ b/cli/azd/pkg/extensions/manager.go @@ -1169,8 +1169,8 @@ func (m *Manager) evaluateDependencyChanges( FromSource: installed.Source, } - // Correlate the child upgrade with its triggering parent. - childCtx, span := tracing.Start(ctx, events.ExtensionUpgradeEvent) + // Correlate the child update with its triggering parent. + childCtx, span := tracing.Start(ctx, events.ExtensionUpdateEvent) span.SetAttributes( fields.ExtensionId.String(dep.Id), fields.ExtensionDependencyOf.String(parentExtension.Id), diff --git a/cli/azd/pkg/extensions/registry_version.go b/cli/azd/pkg/extensions/registry_version.go index 5b4a53603b5..69867be1252 100644 --- a/cli/azd/pkg/extensions/registry_version.go +++ b/cli/azd/pkg/extensions/registry_version.go @@ -28,15 +28,15 @@ func (e *ErrUnsupportedRegistrySchema) Error() string { } // NewUnsupportedRegistrySchemaError wraps an ErrUnsupportedRegistrySchema in an -// ErrorWithSuggestion that guides the user to upgrade azd. +// ErrorWithSuggestion that guides the user to update azd. func NewUnsupportedRegistrySchemaError(schemaErr *ErrUnsupportedRegistrySchema) error { return &errorhandler.ErrorWithSuggestion{ Err: schemaErr, Message: schemaErr.Error(), - Suggestion: "Upgrade azd to the latest version to use this registry", + Suggestion: "Update azd to the latest version to use this registry", Links: []errorhandler.ErrorLink{{ URL: "https://aka.ms/azd/install", - Title: "Install/upgrade azd", + Title: "Install/update azd", }}, } } diff --git a/cli/azd/pkg/extensions/registry_version_test.go b/cli/azd/pkg/extensions/registry_version_test.go index 6bc61055c50..28163617a68 100644 --- a/cli/azd/pkg/extensions/registry_version_test.go +++ b/cli/azd/pkg/extensions/registry_version_test.go @@ -334,7 +334,7 @@ func TestNewUnsupportedRegistrySchemaError(t *testing.T) { suggestionErr, ok := errors.AsType[*errorhandler.ErrorWithSuggestion](err) require.True(t, ok) require.Equal(t, schemaErr.Error(), suggestionErr.Message) - require.Contains(t, suggestionErr.Suggestion, "Upgrade azd") + require.Contains(t, suggestionErr.Suggestion, "Update azd") require.Len(t, suggestionErr.Links, 1) require.Equal(t, "https://aka.ms/azd/install", suggestionErr.Links[0].URL) } diff --git a/cli/azd/pkg/extensions/update_checker.go b/cli/azd/pkg/extensions/update_checker.go index a1da3316c68..787bef8ac34 100644 --- a/cli/azd/pkg/extensions/update_checker.go +++ b/cli/azd/pkg/extensions/update_checker.go @@ -126,10 +126,10 @@ func FormatUpdateWarning(result *UpdateCheckResult) *ux.WarningMessage { ), HidePrefix: false, Hints: []string{ - fmt.Sprintf("To upgrade: %s", - output.WithHighLightFormat("azd extension upgrade %s", result.ExtensionId)), - fmt.Sprintf("To upgrade all: %s", - output.WithHighLightFormat("azd extension upgrade --all")), + fmt.Sprintf("To update: %s", + output.WithHighLightFormat("azd extension update %s", result.ExtensionId)), + fmt.Sprintf("To update all: %s", + output.WithHighLightFormat("azd extension update --all")), }, } } diff --git a/cli/azd/pkg/extensions/update_checker_test.go b/cli/azd/pkg/extensions/update_checker_test.go index 3b66f1d8603..590cc2ecbdc 100644 --- a/cli/azd/pkg/extensions/update_checker_test.go +++ b/cli/azd/pkg/extensions/update_checker_test.go @@ -153,8 +153,8 @@ func Test_FormatUpdateWarning(t *testing.T) { require.Contains(t, warning.Description, "2.0.0") require.False(t, warning.HidePrefix) require.Len(t, warning.Hints, 2) - require.Contains(t, warning.Hints[0], "azd extension upgrade test.extension") - require.Contains(t, warning.Hints[1], "azd extension upgrade --all") + require.Contains(t, warning.Hints[0], "azd extension update test.extension") + require.Contains(t, warning.Hints[1], "azd extension update --all") } func Test_FormatUpdateWarning_NoDisplayName(t *testing.T) { diff --git a/cli/azd/pkg/extensions/update_integration_test.go b/cli/azd/pkg/extensions/update_integration_test.go index fdc3e4a914c..85400ea5da5 100644 --- a/cli/azd/pkg/extensions/update_integration_test.go +++ b/cli/azd/pkg/extensions/update_integration_test.go @@ -166,8 +166,8 @@ func Test_Integration_UpdateCheck_FullFlow(t *testing.T) { require.Contains(t, warning.Description, "2.0.0") require.False(t, warning.HidePrefix) require.Len(t, warning.Hints, 2) - require.Contains(t, warning.Hints[0], "azd extension upgrade test.extension") - require.Contains(t, warning.Hints[1], "azd extension upgrade --all") + require.Contains(t, warning.Hints[0], "azd extension update test.extension") + require.Contains(t, warning.Hints[1], "azd extension update --all") }) } diff --git a/cli/azd/pkg/output/ux/warning_test.go b/cli/azd/pkg/output/ux/warning_test.go index 9f7b9eb911e..629b637eb63 100644 --- a/cli/azd/pkg/output/ux/warning_test.go +++ b/cli/azd/pkg/output/ux/warning_test.go @@ -47,8 +47,8 @@ func TestWarningMessage_ToString_WithHints(t *testing.T) { Description: "Extension update available", HidePrefix: false, Hints: []string{ - "To upgrade: azd extension upgrade test.ext", - "To upgrade all: azd extension upgrade --all", + "To update: azd extension update test.ext", + "To update all: azd extension update --all", }, } @@ -56,8 +56,8 @@ func TestWarningMessage_ToString_WithHints(t *testing.T) { require.Contains(t, result, "WARNING:") require.Contains(t, result, "Extension update available") require.Contains(t, result, "•") - require.Contains(t, result, "To upgrade: azd extension upgrade test.ext") - require.Contains(t, result, "To upgrade all: azd extension upgrade --all") + require.Contains(t, result, "To update: azd extension update test.ext") + require.Contains(t, result, "To update all: azd extension update --all") } func TestWarningMessage_ToString_WithHintsAndIndentation(t *testing.T) { @@ -119,8 +119,8 @@ func TestWarningMessage_MarshalJSON_WithHints(t *testing.T) { Description: "Extension update available", HidePrefix: false, Hints: []string{ - "To upgrade: azd extension upgrade test.ext", - "To upgrade all: azd extension upgrade --all", + "To update: azd extension update test.ext", + "To update all: azd extension update --all", }, } @@ -129,8 +129,8 @@ func TestWarningMessage_MarshalJSON_WithHints(t *testing.T) { jsonStr := string(data) require.Contains(t, jsonStr, "WARNING:") require.Contains(t, jsonStr, "Extension update available") - require.Contains(t, jsonStr, "To upgrade: azd extension upgrade test.ext") - require.Contains(t, jsonStr, "To upgrade all: azd extension upgrade --all") + require.Contains(t, jsonStr, "To update: azd extension update test.ext") + require.Contains(t, jsonStr, "To update all: azd extension update --all") } func TestWarningMessage_MarshalJSON_EmptyHints(t *testing.T) { diff --git a/cli/azd/pkg/tool/detector.go b/cli/azd/pkg/tool/detector.go index f389437f51d..1642b1fe5a5 100644 --- a/cli/azd/pkg/tool/detector.go +++ b/cli/azd/pkg/tool/detector.go @@ -512,7 +512,7 @@ func (d *detector) detectSkill( // DetectSkillAgents returns every configured SkillAgent the skill is // currently installed through (with the version installed via each), in // manifest order. It probes every agent so callers can act on every -// install — e.g. `azd tool upgrade` refreshing the skill on each agent it +// install — e.g. `azd tool update` refreshing the skill on each agent it // was installed to, or per-agent install verification. detectSkill // delegates to it and reports the first matched agent as the aggregate // Installed/InstalledVersion. diff --git a/cli/azd/pkg/tool/installer.go b/cli/azd/pkg/tool/installer.go index 14d7826c6a8..f3d04495c00 100644 --- a/cli/azd/pkg/tool/installer.go +++ b/cli/azd/pkg/tool/installer.go @@ -1150,13 +1150,13 @@ func (i *installer) run( } verb := "Installing" if upgrade { - verb = "Upgrading" + verb = "Updating" } title := fmt.Sprintf("%s %s", verb, tool.Name) cfg.renderer.ShowSpinner(ctx, title, input.Step) result, err := i.runToolInstall(ctx, tool, upgrade) // On a successful upgrade, append the resulting version to the result - // line, mirroring skills — e.g. "Upgrading Azure CLI (v2.0.0)". + // line, mirroring skills — e.g. "Updating Azure CLI (v2.0.0)". doneTitle := title if upgrade && err == nil && result != nil && result.Success && result.InstalledVersion != "" { doneTitle = fmt.Sprintf("%s (v%s)", title, result.InstalledVersion) @@ -1404,7 +1404,7 @@ func (i *installer) runSkill( // latest, which the result line reports. verb := "Installing" if upgrade { - verb = "Upgrading" + verb = "Updating" } var ( succeeded []string @@ -1542,7 +1542,7 @@ func (i *installer) resolveSkillTargets( continue } fmt.Fprintln(os.Stderr, output.WithWarningFormat( - "Skipping upgrade for %s: %s is not installed on it.", + "Skipping update for %s: %s is not installed on it.", agent.DisplayName, tool.Name, )) } @@ -1553,7 +1553,7 @@ func (i *installer) resolveSkillTargets( } return nil, fmt.Errorf( "%s is not installed on any available agent (%s); "+ - "nothing to upgrade", + "nothing to update", tool.Name, strings.Join(onPathNames, ", "), ) } @@ -1588,7 +1588,7 @@ func (i *installer) resolveSkillTargets( "%s is not installed on any available agent", tool.Name, ), - Message: "Cannot upgrade " + tool.Name, + Message: "Cannot update " + tool.Name, Suggestion: fmt.Sprintf( "%s is not installed yet. Install it first:\n\n"+ " azd tool install %s", diff --git a/cli/azd/pkg/tool/installer_test.go b/cli/azd/pkg/tool/installer_test.go index f0a9068ec03..00f8bd24317 100644 --- a/cli/azd/pkg/tool/installer_test.go +++ b/cli/azd/pkg/tool/installer_test.go @@ -248,7 +248,7 @@ func TestRunToolInstall_StepProgress(t *testing.T) { // TestRunToolUpgrade_StepProgress_ShowsVersion verifies that a non-skill // upgrade appends the resulting version to the step result line — the same -// treatment skills get — e.g. "Upgrading Test Tool (v2.64.0)". +// treatment skills get — e.g. "Updating Test Tool (v2.64.0)". func TestRunToolUpgrade_StepProgress_ShowsVersion(t *testing.T) { t.Parallel() @@ -290,8 +290,8 @@ func TestRunToolUpgrade_StepProgress_ShowsVersion(t *testing.T) { require.NoError(t, err) require.True(t, result.Success, "upgrade must succeed; err=%v", result.Error) - assert.Equal(t, []string{"Upgrading Test Tool"}, r.starts) - assert.Equal(t, []string{"Upgrading Test Tool (v2.64.0)"}, r.stops, + assert.Equal(t, []string{"Updating Test Tool"}, r.starts) + assert.Equal(t, []string{"Updating Test Tool (v2.64.0)"}, r.stops, "a non-skill upgrade must report the resulting version, like skills") } @@ -1508,8 +1508,8 @@ func TestRunSkill_Upgrade_StepResultShowsVersion(t *testing.T) { assert.False(t, result.AlreadyUpToDate, "an actual upgrade is not up-to-date") // Spinner title has no version; the result line appends the new version. - assert.Equal(t, []string{"Upgrading Test Azure Skills in copilot"}, r.starts) - assert.Equal(t, []string{"Upgrading Test Azure Skills in copilot (v1.1.86)"}, r.stops) + assert.Equal(t, []string{"Updating Test Azure Skills in copilot"}, r.starts) + assert.Equal(t, []string{"Updating Test Azure Skills in copilot (v1.1.86)"}, r.stops) } // TestRunSkill_Upgrade_AlreadyUpToDate verifies that when the agent reports the @@ -1549,7 +1549,7 @@ func TestRunSkill_Upgrade_AlreadyUpToDate(t *testing.T) { require.True(t, result.Success, "upgrade must succeed; err=%v", result.Error) assert.True(t, result.AlreadyUpToDate, "nothing changed, so already up to date") - assert.Equal(t, []string{"Upgrading Test Azure Skills in copilot"}, r.starts) + assert.Equal(t, []string{"Updating Test Azure Skills in copilot"}, r.starts) assert.Equal(t, []string{"Test Azure Skills in copilot is already up to date (v1.1.86)."}, r.stops) } @@ -1594,7 +1594,7 @@ func TestRunSkill_Upgrade_DetectionLag_NotUpToDate(t *testing.T) { require.True(t, result.Success, "upgrade must succeed; err=%v", result.Error) assert.False(t, result.AlreadyUpToDate, "a reported upgrade must not be marked up-to-date even when detection lags") - assert.Equal(t, []string{"Upgrading Test Azure Skills in copilot (v2.0.0)"}, r.stops) + assert.Equal(t, []string{"Updating Test Azure Skills in copilot (v2.0.0)"}, r.stops) } // TestRunSkill_OutputPrintedBelowStep verifies that when the agent CLI writes @@ -2320,12 +2320,12 @@ func TestRunSkill_Upgrade_PrintsPerAgentHeader(t *testing.T) { }) require.True(t, result.Success, "result.Error=%v", result.Error) - assert.Contains(t, stderr, "Upgrading Test Azure Skills in copilot") - assert.Contains(t, stderr, "Upgrading Test Azure Skills in claude") + assert.Contains(t, stderr, "Updating Test Azure Skills in copilot") + assert.Contains(t, stderr, "Updating Test Azure Skills in claude") } // TestRunSkill_Upgrade_NoAgent_NotInstalled_ReturnsInstallGuidance -// verifies that `azd tool upgrade ` with no --agent, when the +// verifies that `azd tool update ` with no --agent, when the // skill is installed on no available agent, returns a clear "install // first" guidance error instead of falling through to an agent and // attempting to update a plugin that was never installed (which used to diff --git a/cli/azd/pkg/tools/bicep/bicep.go b/cli/azd/pkg/tools/bicep/bicep.go index 1982be30c13..fc8c90b93d5 100644 --- a/cli/azd/pkg/tools/bicep/bicep.go +++ b/cli/azd/pkg/tools/bicep/bicep.go @@ -72,7 +72,7 @@ func newCliWithTransporter( } } -// ensureInstalledOnce checks if bicep is available and downloads/upgrades if needed. +// ensureInstalledOnce checks if bicep is available and downloads or updates it if needed. // This is safe to call multiple times; successful installation is cached and failed attempts are retried. func (cli *Cli) ensureInstalledOnce(ctx context.Context) error { return cli.installInit.Do(func() error { @@ -123,11 +123,11 @@ func (cli *Cli) ensureInstalled(ctx context.Context) error { log.Printf("installed bicep version %s is older than %s; updating.", ver.String(), Version.String()) if err := runStep( - ctx, cli.console, "Upgrading Bicep", func() error { + ctx, cli.console, "Updating Bicep", func() error { return downloadBicep(ctx, cli.transporter, Version, bicepPath) }, ); err != nil { - return fmt.Errorf("upgrading bicep: %w", err) + return fmt.Errorf("updating bicep: %w", err) } } diff --git a/cli/azd/pkg/tools/bicep/bicep_test.go b/cli/azd/pkg/tools/bicep/bicep_test.go index d59a08d5f26..7dfcffb8d37 100644 --- a/cli/azd/pkg/tools/bicep/bicep_test.go +++ b/cli/azd/pkg/tools/bicep/bicep_test.go @@ -130,13 +130,13 @@ func TestNewBicepCliWillUpgrade(t *testing.T) { require.Equal(t, mockinput.SpinnerOp{ Op: mockinput.SpinnerOpShow, - Message: "Upgrading Bicep", + Message: "Updating Bicep", Format: input.Step, }, mockContext.Console.SpinnerOps()[0]) require.Equal(t, mockinput.SpinnerOp{ Op: mockinput.SpinnerOpStop, - Message: "Upgrading Bicep", + Message: "Updating Bicep", Format: input.StepDone, }, mockContext.Console.SpinnerOps()[1]) diff --git a/cli/azd/pkg/tools/pack/pack.go b/cli/azd/pkg/tools/pack/pack.go index 2f4f98f5912..931c04ce2f2 100644 --- a/cli/azd/pkg/tools/pack/pack.go +++ b/cli/azd/pkg/tools/pack/pack.go @@ -167,12 +167,12 @@ func (cli *Cli) ensureInstalled(ctx context.Context) error { if ver.LT(Version) { log.Printf("installed pack version %s is older than %s; updating.", ver.String(), Version.String()) - msg := "Upgrading pack" + msg := "Updating pack" cli.console.ShowSpinner(ctx, msg, input.Step) err := downloadPack(ctx, cli.transporter, Version, cli.extract, cliPath) cli.console.StopSpinner(ctx, "", input.Step) if err != nil { - return fmt.Errorf("upgrading pack: %w", err) + return fmt.Errorf("updating pack: %w", err) } } diff --git a/cli/azd/resources/error_suggestions.yaml b/cli/azd/resources/error_suggestions.yaml index 7b7db9155cf..a71a3a4ad20 100644 --- a/cli/azd/resources/error_suggestions.yaml +++ b/cli/azd/resources/error_suggestions.yaml @@ -601,10 +601,10 @@ rules: # catch-all for any alternative code paths where the error surfaces unwrapped. - errorType: "ErrUnsupportedRegistrySchema" message: "The extension registry uses a schema version not supported by this version of azd." - suggestion: "Upgrade azd to the latest version to use this registry." + suggestion: "Update azd to the latest version to use this registry." links: - url: "https://aka.ms/azd/install" - title: "Install/upgrade azd" + title: "Install/update azd" # ============================================================================ # Text Pattern Rules — Broad/generic patterns (least specific, must be last) diff --git a/docs/architecture/telemetry.md b/docs/architecture/telemetry.md index bee6971d45f..61ae7a75e14 100644 --- a/docs/architecture/telemetry.md +++ b/docs/architecture/telemetry.md @@ -182,7 +182,7 @@ flowchart LR - Validation: `ext.validation.*` - Auth: `ext.auth.*` - Dependency: `ext.dependency.*` -- Extension lifecycle events: `ext.install`, `ext.upgrade`, `ext.promote` +- Extension lifecycle events: `ext.install`, `ext.update`, `ext.promote` ## Consent & Privacy diff --git a/docs/guides/creating-an-extension.md b/docs/guides/creating-an-extension.md index c47d92ee047..0b8b2a2ec03 100644 --- a/docs/guides/creating-an-extension.md +++ b/docs/guides/creating-an-extension.md @@ -76,7 +76,7 @@ For extensions that are still in development or preview, consider publishing to azd extension install my.extension --source dev ``` -4. Once your extension is stable and meets the quality bar, submit a follow-up PR to add it to `cli/azd/extensions/registry.json`. Users who installed from the dev registry will be **automatically promoted** to the main registry on their next `azd extension upgrade`. +4. Once your extension is stable and meets the quality bar, submit a follow-up PR to add it to `cli/azd/extensions/registry.json`. Users who installed from the dev registry will be **automatically promoted** to the main registry on their next `azd extension update`. > [!NOTE] > Extensions in the dev registry have no stability guarantees, are unsigned, and are not covered by Azure support. This is expected and appropriate for pre-release testing. See the [Dev/Experimental Extension Registry](../../cli/azd/docs/extensions/extension-resolution-and-versioning.md#devexperimental-extension-registry) guide for full details. diff --git a/docs/reference/telemetry-data.md b/docs/reference/telemetry-data.md index 202e8cce7d5..1a948ad3017 100644 --- a/docs/reference/telemetry-data.md +++ b/docs/reference/telemetry-data.md @@ -72,7 +72,7 @@ Commands follow the pattern `cmd.` where spaces become dots. |-------|-------------| | `ext.run` | Extension command execution | | `ext.install` | Extension installation | -| `ext.upgrade` | Extension upgrade attempt | +| `ext.update` | Extension update attempt | | `ext.promote` | Registry promotion (e.g., dev → main) | ### Agent & Copilot Events @@ -449,22 +449,22 @@ Emitted at provision start by the `microsoft.foundry` provisioning provider (the | `extension.id` | string | Extension identifier | | `extension.version` | string | Extension version | | `extension.installed` | string[] | List of installed extensions (`id@version`) | -| `extension.version.from` | string | Version before an upgrade or promotion (`ext.upgrade`, `ext.promote`) | -| `extension.version.to` | string | Version after an upgrade or promotion (`ext.upgrade`, `ext.promote`) | -| `extension.source` | string | Registry source used for an upgrade (`ext.upgrade`) | -| `extension.source.kind` | string | Kind of `--source` argument: `none`, `registered`, or `location` (`azd extension list`, `show`, `install`, `upgrade`) | +| `extension.version.from` | string | Version before an update or promotion (`ext.update`, `ext.promote`) | +| `extension.version.to` | string | Version after an update or promotion (`ext.update`, `ext.promote`) | +| `extension.source` | string | Registry source used for an update (`ext.update`) | +| `extension.source.kind` | string | Kind of `--source` argument: `none`, `registered`, or `location` (`azd extension list`, `show`, `install`, `update`) | | `extension.source.from` | string | Registry source before a promotion (`ext.promote`) | | `extension.source.to` | string | Registry source after a promotion (`ext.promote`) | -| `extension.upgrade.duration_ms` | measurement | Duration (ms) of a single upgrade (`ext.upgrade`) | -| `extension.upgrade.outcome` | string | Upgrade result status (`ext.upgrade`) | -| `extension.dependency_of` | string | Parent extension ID when an extension is upgraded as a dependency (`ext.upgrade`) | -| `extension.dependency_upgrade_count` | measurement | Number of dependency extensions upgraded recursively (`ext.upgrade`) | +| `extension.update.duration_ms` | measurement | Duration (ms) of a single update (`ext.update`) | +| `extension.update.outcome` | string | Update result status (`ext.update`) | +| `extension.dependency_of` | string | Parent extension ID when an extension is updated as a dependency (`ext.update`) | +| `extension.dependency_update_count` | measurement | Number of dependency extensions updated recursively (`ext.update`) |
Tool Management (azd tool) -Fields for the `azd tool` feature, including active `install`/`upgrade`/`check` operations and the reserved first-run contract for azd-managed developer tools. These are **distinct** from the [Tool Invocation Attributes](#tool-invocation-attributes-external-cli-tools) above (which describe external processes azd shells out to). +Fields for the `azd tool` feature, including active `install`/`update`/`check` operations and the reserved first-run contract for azd-managed developer tools. These are **distinct** from the [Tool Invocation Attributes](#tool-invocation-attributes-external-cli-tools) above (which describe external processes azd shells out to). > **Privacy:** only built-in tool IDs (e.g. `az-cli`, `vscode-bicep`) and version strings are captured. No file paths, no user-identifiable data, and no raw per-tool error text — failed tool IDs are recorded, but error detail stays with the global error middleware. @@ -489,7 +489,7 @@ The first-run middleware is not currently registered, so these fields are not em | `tool.firstrun.install_failed_ids` | string | Comma-separated tool IDs that failed during first-run | | `tool.firstrun.install_duration_ms` | measurement | Total first-run install duration (ms) | -**Install / upgrade / uninstall / check operations:** +**Install / update / uninstall / check operations:** | Field Key | Type | Description | |-----------|------|-------------| @@ -497,14 +497,14 @@ The first-run middleware is not currently registered, so these fields are not em | `tool.ids` | string | Comma-separated tool IDs for a batch operation | | `tool.dry_run` | string | Whether `--dry-run` was specified | | `tool.install.strategy` | string | Install strategy used. Package-manager values come from the tool manifest (`winget`, `brew`, `apt`, `npm`, `code`); the installer may also report `direct-download`, `command`, or `manual` (no available manager) | -| `tool.install.success` | string | Whether a single-target install, upgrade, or uninstall succeeded | -| `tool.install.success_count` | measurement | Tools that succeeded in a batch install/upgrade/uninstall | -| `tool.install.failure_count` | measurement | Tools that failed in a batch install/upgrade/uninstall | -| `tool.install.failed_ids` | string | Comma-separated tool IDs whose install/upgrade/uninstall failed | -| `tool.install.duration_ms` | measurement | Total install/upgrade/uninstall duration (ms) | -| `tool.upgrade.from_version` | string | Previous version (single-target upgrade) | -| `tool.upgrade.to_version` | string | New version after a successful upgrade (single-target) | -| `tool.check.updates_available` | measurement | Installed tools with an available upgrade (`azd tool check`) | +| `tool.install.success` | string | Whether a single-target install, update, or uninstall succeeded | +| `tool.install.success_count` | measurement | Tools that succeeded in a batch install/update/uninstall | +| `tool.install.failure_count` | measurement | Tools that failed in a batch install/update/uninstall | +| `tool.install.failed_ids` | string | Comma-separated tool IDs whose install/update/uninstall failed | +| `tool.install.duration_ms` | measurement | Total install/update/uninstall duration (ms) | +| `tool.update.from_version` | string | Previous version (single-target update) | +| `tool.update.to_version` | string | New version after a successful update (single-target) | +| `tool.check.updates_available` | measurement | Installed tools with an available update (`azd tool check`) |
@@ -698,7 +698,7 @@ How to find telemetry for a given feature area. Start here if you know the featu | **Provisioning (IaC)** | `cmd.provision`, `cmd.up`, `cmd.down`, `arm.deploy.*`, `arm.validate.*` | `infra.provider` (`bicep`/`terraform`/`arm`/`pulumi`/custom; slice of each distinct provider for multi-layer projects) | Provision success, ARM errors, duration | | **Authentication** | `cmd.auth.login` | `auth.method` | Auth method usage, failure rates | | **CI/CD Pipelines** | `cmd.pipeline.config` | `pipeline.provider` | Pipeline setup adoption | -| **Extensions** | `ext.run`, `ext.install`, `ext.upgrade` | `extension.id`, `extension.version`, `extension.installed` | Extension adoption, errors | +| **Extensions** | `ext.run`, `ext.install`, `ext.update` | `extension.id`, `extension.version`, `extension.installed` | Extension adoption, errors | | **MCP** | `mcp.` | `mcp.client.name`, `mcp.client.version` | Tool usage by client | | **Agentic (Copilot)** | `copilot.initialize`, `copilot.session` | `copilot.mode`, `copilot.init.model`, `copilot.message.*` | Session counts, token usage | | **Agent Troubleshooting** | `agent.troubleshoot` | `agent.fix.attempts` | Auto-fix adoption, retry counts | @@ -707,7 +707,7 @@ How to find telemetry for a given feature area. Start here if you know the featu | **Self-Update** | `cmd.update` | `update.installMethod`, `update.fromVersion` | Update adoption | | **Hooks** | `hooks.exec` | `hooks.name`, `hooks.type`, `hooks.kind` | Hook usage by type | | **Container Build** | `container.publish`, `container.remotebuild`, `tools.pack.build` | `pack.builder.image` | Build method usage, success rates | -| **Tool Management (`azd tool`)** | `cmd.tool.install`, `cmd.tool.upgrade`, `cmd.tool.uninstall`, `cmd.tool.check` | `tool.id`, `tool.install.strategy` | Install/upgrade/uninstall success, upgrade availability | +| **Tool Management (`azd tool`)** | `cmd.tool.install`, `cmd.tool.update`, `cmd.tool.uninstall`, `cmd.tool.check` | `tool.id`, `tool.install.strategy` | Install/update/uninstall success, update availability | ## See Also diff --git a/docs/specs/metrics-audit/feature-telemetry-matrix.md b/docs/specs/metrics-audit/feature-telemetry-matrix.md index 024971b2d32..10cb1ab82b4 100644 --- a/docs/specs/metrics-audit/feature-telemetry-matrix.md +++ b/docs/specs/metrics-audit/feature-telemetry-matrix.md @@ -30,9 +30,9 @@ These commands emit attributes or events beyond the global middleware span. |---------|---------------------|-------| | `init` | `init.method` (template / app / project / environment / copilot), `appinit.detected.databases`, `appinit.detected.services`, `appinit.confirmed.databases`, `appinit.confirmed.services`, `appinit.modify_add.count`, `appinit.modify_remove.count`, `appinit.lastStep` | Comprehensive coverage via `SetUsageAttributes` and `repository/app_init.go` | | `update` | `update.installMethod`, `update.channel`, `update.fromVersion`, `update.toVersion`, `update.result` | Result codes cover success, failure, and skip reasons | -| Extensions (dynamic) | `extension.id`, `extension.version`, `extension.version.from`, `extension.version.to`, `extension.source`, `extension.source.kind`, `extension.source.from`, `extension.source.to`, `extension.dependency_of`, `extension.dependency_upgrade_count`, `extension.upgrade.outcome`, `extension.upgrade.duration_ms` + trace-context propagation to child process | Covers `ext.run`, `ext.install`, `ext.upgrade`, `ext.promote` events; `extension.source.kind` distinguishes no source, registered source, and direct location usage for extension list/show/install/upgrade | +| Extensions (dynamic) | `extension.id`, `extension.version`, `extension.version.from`, `extension.version.to`, `extension.source`, `extension.source.kind`, `extension.source.from`, `extension.source.to`, `extension.dependency_of`, `extension.dependency_update_count`, `extension.update.outcome`, `extension.update.duration_ms` + trace-context propagation to child process | Covers `ext.run`, `ext.install`, `ext.update`, `ext.promote` events; `extension.source.kind` distinguishes no source, registered source, and direct location usage for extension list/show/install/update | | `mcp start` | Per-tool spans via `tracing.Start` with `mcp.client.name`, `mcp.client.version` | MCP event prefix `mcp.*` | -| `tool install` / `tool upgrade` / `tool uninstall` / `tool check` / `tool list` / `tool show` | `tool.id`, `tool.ids`, `tool.dry_run`, `tool.install.strategy`, `tool.install.success`, `tool.install.success_count`, `tool.install.failure_count`, `tool.install.failed_ids`, `tool.install.duration_ms`, `tool.upgrade.from_version`, `tool.upgrade.to_version`, `tool.check.updates_available` | Comprehensive coverage in `cli/azd/cmd/tool.go`; install/upgrade emit `tools.pack.build` spans for pack-based tools | +| `tool install` / `tool update` / `tool uninstall` / `tool check` / `tool list` / `tool show` | `tool.id`, `tool.ids`, `tool.dry_run`, `tool.install.strategy`, `tool.install.success`, `tool.install.success_count`, `tool.install.failure_count`, `tool.install.failed_ids`, `tool.install.duration_ms`, `tool.update.from_version`, `tool.update.to_version`, `tool.check.updates_available` | Comprehensive coverage in `cli/azd/cmd/tool.go`; install/update emit `tools.pack.build` spans for pack-based tools | | `copilot` (agent) | `copilot.initialize` event (model + reasoning config), `copilot.session` event (session create/resume) | Emitted from `internal/agent/copilot_agent.go`; covers the experimental copilot agent surface | | `provision` | `validation.provision` event (provision validation outcome + 6 fields), 8 `arm.*` events (subscription / resource-group deploy / stack-deploy / what-if / validate), `aks.postprovision.skip`, per-layer `provision.layer.*` counts (`count`, `max_parallel`, `safe_fallback_count`, `explicit_dependson_count`) when multi-layer infra is used | Telemetry added across `internal/cmd/provision_*.go` and the ARM deployment client | | `deploy` / `publish` / `package` | `deploy.appservice.zip` event (zip-deploy outcome), `container.credentials` / `container.publish` / `container.remotebuild` events for container-based services | Per-service-target instrumentation; container events emitted from container-app and ACR push paths | @@ -87,8 +87,8 @@ These commands emit attributes or events beyond the global middleware span. | **Copilot Consent** | | | | | | | `copilot consent` | `list`, `revoke`, `grant` | ✅ | ❌ | ❌ | Low priority | | **Extension Management** | | | | | | -| `extension` | `list`, `show`, `install`, `uninstall`, `upgrade` | ✅ | ✅ | ✅ | Covered by `extension.*` fields and `ext.install`, `ext.upgrade`, `ext.promote` events; `extension.source.kind` tracks `--source` argument kind for list/show/install/upgrade | -| `extension source` | `list`, `add`, `remove`, `validate` | ✅ | ❌ | ❌ | Subcommand name in the global span captures the operation; `extension.source*` attributes are recorded by `extension upgrade` / `extension promote`, not by this subcommand | +| `extension` | `list`, `show`, `install`, `uninstall`, `update` | ✅ | ✅ | ✅ | Covered by `extension.*` fields and `ext.install`, `ext.update`, `ext.promote` events; `extension.source.kind` tracks `--source` argument kind for list/show/install/update | +| `extension source` | `list`, `add`, `remove`, `validate` | ✅ | ❌ | ❌ | Subcommand name in the global span captures the operation; `extension.source*` attributes are recorded by `extension update` / `extension promote`, not by this subcommand | | **Init** | | | | | | | `init` | — | ✅ | ✅ | ✅ | Comprehensive coverage via `appinit.*` fields | | **Update** | | | | | | @@ -98,7 +98,7 @@ These commands emit attributes or events beyond the global middleware span. | **Tool Management** | | | | | | | `tool list` | — | ✅ | ✅ | ❌ | `tool.ids` listed for visibility into per-row outputs | | `tool install` | — | ✅ | ✅ | ✅ | `tool.id`, `tool.install.strategy`, `tool.install.success`, `tool.install.success_count`, `tool.install.failure_count`, `tool.install.failed_ids`, `tool.install.duration_ms`, `tool.dry_run`; `tools.pack.build` for pack-based tools | -| `tool upgrade` | — | ✅ | ✅ | ✅ | All `tool.install.*` plus `tool.upgrade.from_version`, `tool.upgrade.to_version` | +| `tool update` | — | ✅ | ✅ | ✅ | All `tool.install.*` plus `tool.update.from_version`, `tool.update.to_version` | | `tool uninstall` | — | ✅ | ✅ | ✅ | `tool.id`/`tool.ids`, `tool.dry_run`, and the `tool.install.*` aggregate/per-tool fields (no version fields) | | `tool check` | — | ✅ | ✅ | ❌ | `tool.check.updates_available` (count) | | `tool show` | — | ✅ | ✅ | ❌ | `tool.id` | @@ -124,8 +124,8 @@ command-specific telemetry fields provide analytical value beyond the command na | Pipeline auth | `pipeline.auth` | `pipeline config` | Distinguishes federated vs client-credentials | | Infra provider | `infra.provider` | `infra generate`, `infra synth`, `provision`, `up`, `down` | provision/up/down: sorted, de-duplicated string slice of resolved providers — `bicep`/`terraform`/`arm`/`pulumi` verbatim, `custom` for extension providers (raw name not emitted); multi-layer projects that combine providers record each distinct value (e.g. `["bicep","terraform"]`). `infra generate`/`synth`: the value read from azure.yaml's `infra.provider` emitted directly as a single string (`bicep`/`terraform`/`arm`/`pulumi`, `auto` when unset, or `custom` for extension providers — raw name not emitted) | | Tool ID | `tool.id` / `tool.ids` | `tool *` | Identifies which managed tool (e.g., bicep, gh, kubectl) the command acted on | -| Tool install metrics | `tool.install.*` | `tool install`, `tool upgrade`, `tool uninstall` | Success count, failure count, duration, strategy — quantitative install health | -| Tool upgrade versions | `tool.upgrade.from_version`, `tool.upgrade.to_version` | `tool upgrade` | Tracks adoption of new tool versions | +| Tool install metrics | `tool.install.*` | `tool install`, `tool update`, `tool uninstall` | Success count, failure count, duration, strategy — quantitative install health | +| Tool update versions | `tool.update.from_version`, `tool.update.to_version` | `tool update` | Tracks adoption of new tool versions | | Provision validation outcome | `validation.provision.outcome` (+ peer fields incl. `validation.provision.check_type`) | `provision` | Distinguishes passed / warnings-accepted / canceled local validation; `check_type` separates the provider-agnostic `provision` dispatch from the Bicep `arm-provision` dispatch (both share the event) | | ARM deployment events | `arm.deploy.*`, `arm.stack.deploy.*`, `arm.whatif.*`, `arm.validate.*` | `provision` | Distinguishes deployment scope (subscription vs resource-group) and operation kind (deploy / stack / what-if / validate) | | Container events | `container.credentials`, `container.publish`, `container.remotebuild` | `package`, `deploy` | Per-stage container lifecycle for container-based services | diff --git a/docs/specs/metrics-audit/telemetry-schema.md b/docs/specs/metrics-audit/telemetry-schema.md index 402e4de9f73..11fcb9042b4 100644 --- a/docs/specs/metrics-audit/telemetry-schema.md +++ b/docs/specs/metrics-audit/telemetry-schema.md @@ -17,7 +17,7 @@ OpenTelemetry span name or event name. | `AgentTroubleshootEvent` | `agent.troubleshoot` | Agent troubleshooting event | | `ExtensionRunEvent` | `ext.run` | Extension execution event | | `ExtensionInstallEvent` | `ext.install` | Extension install/upgrade event | -| `ExtensionUpgradeEvent` | `ext.upgrade` | Single extension upgrade attempt | +| `ExtensionUpdateEvent` | `ext.update` | Single extension update attempt | | `ExtensionPromoteEvent` | `ext.promote` | Extension registry promotion (e.g., dev → main) | | `CopilotInitializeEvent` | `copilot.initialize` | Copilot initialization event | | `CopilotSessionEvent` | `copilot.session` | Copilot session lifecycle event | @@ -210,10 +210,10 @@ not emitted by azd spans. | Extension source kind | `extension.source.kind` | SystemMetadata | FeatureInsight | Allowed values: `none`, `registered`, `location` | | Extension source from | `extension.source.from` | SystemMetadata | FeatureInsight | Registry source before a promotion | | Extension source to | `extension.source.to` | SystemMetadata | FeatureInsight | Registry source after a promotion | -| Upgrade duration | `extension.upgrade.duration_ms` | SystemMetadata | PerformanceAndHealth | **Measurement** — time in ms for one upgrade | -| Upgrade outcome | `extension.upgrade.outcome` | SystemMetadata | FeatureInsight | Upgrade result status | +| Update duration | `extension.update.duration_ms` | SystemMetadata | PerformanceAndHealth | **Measurement** — time in ms for one update | +| Update outcome | `extension.update.outcome` | SystemMetadata | FeatureInsight | Update result status | | Dependency of | `extension.dependency_of` | SystemMetadata | FeatureInsight | Parent extension for a dependency upgrade | -| Dependency upgrade count | `extension.dependency_upgrade_count` | SystemMetadata | FeatureInsight | Recursive dependency upgrade count | +| Dependency update count | `extension.dependency_update_count` | SystemMetadata | FeatureInsight | Recursive dependency update count | ### Update @@ -322,8 +322,8 @@ remain defined to support a possible future redesign without changing the teleme | Install failure count | `tool.install.failure_count` | SystemMetadata | FeatureInsight | **Measurement** — number of tools that failed in a batch | | Install failed IDs | `tool.install.failed_ids` | SystemMetadata | FeatureInsight | Comma-separated built-in tool IDs whose install/upgrade failed. Per-tool error messages are intentionally not captured | | Install duration | `tool.install.duration_ms` | SystemMetadata | FeatureInsight | **Measurement** — total install/upgrade duration in ms | -| Upgrade from version | `tool.upgrade.from_version` | SystemMetadata | FeatureInsight | Prior version (single-target upgrades) | -| Upgrade to version | `tool.upgrade.to_version` | SystemMetadata | FeatureInsight | New version after a successful upgrade | +| Update from version | `tool.update.from_version` | SystemMetadata | FeatureInsight | Prior version (single-target updates) | +| Update to version | `tool.update.to_version` | SystemMetadata | FeatureInsight | New version after a successful update | | Updates available | `tool.check.updates_available` | SystemMetadata | FeatureInsight | **Measurement** — number of installed tools with an available upgrade | ### Provision Validation