示例#1
0
        /// <summary>
        /// The internal implementation to perform user action.
        /// </summary>
        /// <param name="resolveActionsAsync">A function that returns a task that resolves the user
        /// action into project actions.</param>
        /// <param name="executeActionsAsync">A function that returns a task that executes
        /// the project actions.</param>
        private async Task PerformActionImplAsync(
            INuGetUI uiService,
            Func <SourceCacheContext, Task <IReadOnlyList <ResolvedAction> > > resolveActionsAsync,
            Func <IReadOnlyList <ResolvedAction>, SourceCacheContext, Task> executeActionsAsync,
            NuGetOperationType operationType,
            UserAction userAction,
            CancellationToken token)
        {
            var status       = NuGetOperationStatus.Succeeded;
            var startTime    = DateTimeOffset.Now;
            var packageCount = 0;

            bool continueAfterPreview = true;
            bool acceptedLicense      = true;

            List <string> removedPackages = null;
            HashSet <Tuple <string, string> > existingPackages   = new HashSet <Tuple <string, string> >();
            List <Tuple <string, string> >    addedPackages      = null;
            List <Tuple <string, string> >    updatedPackagesOld = null;
            List <Tuple <string, string> >    updatedPackagesNew = null;

            // Enable granular level telemetry events for nuget ui operation
            uiService.ProjectContext.OperationId = Guid.NewGuid();

            Stopwatch packageEnumerationTime = new Stopwatch();

            packageEnumerationTime.Start();
            try
            {
                // collect the install state of the existing packages
                foreach (var project in uiService.Projects)
                {
                    var result = await project.GetInstalledPackagesAsync(token);

                    foreach (var package in result)
                    {
                        Tuple <string, string> packageInfo = new Tuple <string, string>(package.PackageIdentity.Id, (package.PackageIdentity.Version == null ? "" : package.PackageIdentity.Version.ToNormalizedString()));
                        if (!existingPackages.Contains(packageInfo))
                        {
                            existingPackages.Add(packageInfo);
                        }
                    }
                }
            }
            catch (Exception)
            {
                // don't teardown the process if we have a telemetry failure
            }
            packageEnumerationTime.Stop();

            await _lockService.ExecuteNuGetOperationAsync(async() =>
            {
                try
                {
                    uiService.BeginOperation();

                    var acceptedFormat = await CheckPackageManagementFormat(uiService, token);
                    if (!acceptedFormat)
                    {
                        return;
                    }

                    TelemetryServiceUtility.StartOrResumeTimer();

                    using (var sourceCacheContext = new SourceCacheContext())
                    {
                        var actions = await resolveActionsAsync(sourceCacheContext);
                        var results = GetPreviewResults(actions);

                        if (operationType == NuGetOperationType.Uninstall)
                        {
                            // removed packages don't have version info
                            removedPackages = results.SelectMany(result => result.Deleted)
                                              .Select(package => package.Id)
                                              .Distinct()
                                              .ToList();
                            packageCount = removedPackages.Count;
                        }
                        else
                        {
                            // log rich info about added packages
                            addedPackages = results.SelectMany(result => result.Added)
                                            .Select(package => new Tuple <string, string>(package.Id, (package.Version == null ? "" : package.Version.ToNormalizedString())))
                                            .Distinct()
                                            .ToList();
                            var addCount = addedPackages.Count;

                            //updated packages can have an old and a new id.
                            updatedPackagesOld = results.SelectMany(result => result.Updated)
                                                 .Select(package => new Tuple <string, string>(package.Old.Id, (package.Old.Version == null ? "" : package.Old.Version.ToNormalizedString())))
                                                 .Distinct()
                                                 .ToList();
                            updatedPackagesNew = results.SelectMany(result => result.Updated)
                                                 .Select(package => new Tuple <string, string>(package.New.Id, (package.New.Version == null ? "" : package.New.Version.ToNormalizedString())))
                                                 .Distinct()
                                                 .ToList();
                            var updateCount = updatedPackagesNew.Count;

                            // update packages count
                            packageCount = addCount + updateCount;

                            if (updateCount > 0)
                            {
                                // set operation type to update when there are packages being updated
                                operationType = NuGetOperationType.Update;
                            }
                        }

                        TelemetryServiceUtility.StopTimer();

                        // Show the preview window.
                        if (uiService.DisplayPreviewWindow)
                        {
                            var shouldContinue = uiService.PromptForPreviewAcceptance(results);
                            if (!shouldContinue)
                            {
                                continueAfterPreview = false;
                                return;
                            }
                        }

                        TelemetryServiceUtility.StartOrResumeTimer();

                        // Show the license acceptance window.
                        var accepted = await CheckLicenseAcceptanceAsync(uiService, results, token);

                        TelemetryServiceUtility.StartOrResumeTimer();

                        if (!accepted)
                        {
                            acceptedLicense = false;
                            return;
                        }

                        // Warn about the fact that the "dotnet" TFM is deprecated.
                        if (uiService.DisplayDeprecatedFrameworkWindow)
                        {
                            var shouldContinue = ShouldContinueDueToDotnetDeprecation(uiService, actions, token);

                            TelemetryServiceUtility.StartOrResumeTimer();

                            if (!shouldContinue)
                            {
                                return;
                            }
                        }

                        if (!token.IsCancellationRequested)
                        {
                            // execute the actions
                            await executeActionsAsync(actions, sourceCacheContext);

                            // fires ActionsExecuted event to update the UI
                            uiService.OnActionsExecuted(actions);
                        }
                        else
                        {
                            status = NuGetOperationStatus.Cancelled;
                        }
                    }
                }
                catch (System.Net.Http.HttpRequestException ex)
                {
                    status = NuGetOperationStatus.Failed;
                    if (ex.InnerException != null)
                    {
                        uiService.ShowError(ex.InnerException);
                    }
                    else
                    {
                        uiService.ShowError(ex);
                    }
                }
                catch (Exception ex)
                {
                    status = NuGetOperationStatus.Failed;
                    uiService.ShowError(ex);
                }
                finally
                {
                    TelemetryServiceUtility.StopTimer();

                    var duration = TelemetryServiceUtility.GetTimerElapsedTime();

                    uiService.ProjectContext.Log(MessageLevel.Info,
                                                 string.Format(CultureInfo.CurrentCulture, Resources.Operation_TotalTime, duration));

                    uiService.EndOperation();

                    // don't show "Succeeded" if we actually cancelled...
                    if ((!continueAfterPreview) || (!acceptedLicense))
                    {
                        if (status == NuGetOperationStatus.Succeeded)
                        {
                            status = NuGetOperationStatus.Cancelled;
                        }
                    }

                    PackageLoadContext plc = new PackageLoadContext(sourceRepositories: null, isSolution: false, uiService.UIContext);
                    var frameworks         = plc.GetSupportedFrameworks().ToList();

                    var actionTelemetryEvent = VSTelemetryServiceUtility.GetActionTelemetryEvent(
                        uiService.ProjectContext.OperationId.ToString(),
                        uiService.Projects,
                        operationType,
                        OperationSource.UI,
                        startTime,
                        status,
                        packageCount,
                        duration.TotalSeconds);

                    var nuGetUI = uiService as NuGetUI;
                    AddUiActionEngineTelemetryProperties(
                        actionTelemetryEvent,
                        continueAfterPreview,
                        acceptedLicense,
                        userAction,
                        nuGetUI?.SelectedIndex,
                        nuGetUI?.RecommendedCount,
                        nuGetUI?.RecommendPackages,
                        nuGetUI?.RecommenderVersion,
                        existingPackages,
                        addedPackages,
                        removedPackages,
                        updatedPackagesOld,
                        updatedPackagesNew,
                        frameworks);

                    actionTelemetryEvent["InstalledPackageEnumerationTimeInMilliseconds"] = packageEnumerationTime.ElapsedMilliseconds;

                    TelemetryActivity.EmitTelemetryEvent(actionTelemetryEvent);
                }
            }, token);
        }
示例#2
0
        internal static async Task <string> DoUpgradeAsync(
            INuGetUIContext context,
            INuGetUI uiService,
            NuGetProject nuGetProject,
            IEnumerable <NuGetProjectUpgradeDependencyItem> upgradeDependencyItems,
            IEnumerable <PackageIdentity> notFoundPackages,
            IProgress <ProgressDialogData> progress,
            CancellationToken token)
        {
            var startTime     = DateTimeOffset.Now;
            var packagesCount = 0;
            var status        = NuGetOperationStatus.Succeeded;


            using (var telemetry = new TelemetryActivity(Guid.Empty))
            {
                try
                {
                    // 0. Fail if any package was not found
                    if (notFoundPackages.Any())
                    {
                        status = NuGetOperationStatus.Failed;
                        var notFoundPackageIds = string.Join(",", notFoundPackages.Select(t => t.Id));
                        uiService.ProjectContext.Log(MessageLevel.Error, string.Format(CultureInfo.CurrentCulture, Resources.Migrator_PackageNotFound, notFoundPackageIds));
                        return(null);
                    }

                    // 1. Backup files (csproj and packages.config) that will change
                    var solutionManager           = context.SolutionManager;
                    var msBuildNuGetProject       = (MSBuildNuGetProject)nuGetProject;
                    var msBuildNuGetProjectSystem = msBuildNuGetProject.ProjectSystem;
                    var backupPath = string.Empty;
                    try
                    {
                        backupPath = CreateBackup(msBuildNuGetProject, solutionManager.SolutionDirectory);
                    }
                    catch (Exception ex)
                    {
                        status = NuGetOperationStatus.Failed;
                        // log error message
                        uiService.ShowError(ex);
                        uiService.ProjectContext.Log(MessageLevel.Info,
                                                     string.Format(CultureInfo.CurrentCulture, Resources.Upgrader_BackupFailed));

                        return(null);
                    }


                    // 2. Uninstall all packages currently in packages.config
                    var progressData = new ProgressDialogData(Resources.NuGetUpgrade_WaitMessage, Resources.NuGetUpgrade_Progress_Uninstalling);
                    progress.Report(progressData);

                    // Don't uninstall packages we couldn't find - that will just fail
                    var actions = upgradeDependencyItems.Select(d => d.Package)
                                  .Where(p => !notFoundPackages.Contains(p))
                                  .Select(t => NuGetProjectAction.CreateUninstallProjectAction(t, nuGetProject));

                    try
                    {
                        await context.PackageManager.ExecuteNuGetProjectActionsAsync(nuGetProject, actions, uiService.ProjectContext, NullSourceCacheContext.Instance, CancellationToken.None);
                    }
                    catch (Exception ex)
                    {
                        status = NuGetOperationStatus.Failed;
                        // log error message
                        uiService.ShowError(ex);
                        uiService.ProjectContext.Log(MessageLevel.Info,
                                                     string.Format(CultureInfo.CurrentCulture, Resources.Upgrade_UninstallFailed));

                        return(null);
                    }

                    // Reload the project, and get a reference to the reloaded project
                    var uniqueName = msBuildNuGetProjectSystem.ProjectUniqueName;
                    await msBuildNuGetProject.SaveAsync(token);

                    nuGetProject = await solutionManager.GetNuGetProjectAsync(uniqueName);

                    nuGetProject = await solutionManager.UpgradeProjectToPackageReferenceAsync(nuGetProject);

                    // Ensure we use the updated project for installing, and don't display preview or license acceptance windows.
                    context.Projects = new[] { nuGetProject };
                    var nuGetUI = (NuGetUI)uiService;
                    nuGetUI.Projects             = new[] { nuGetProject };
                    nuGetUI.DisplayPreviewWindow = false;

                    // 4. Install the requested packages
                    var ideExecutionContext = uiService.ProjectContext.ExecutionContext as IDEExecutionContext;
                    if (ideExecutionContext != null)
                    {
                        await ideExecutionContext.SaveExpandedNodeStates(solutionManager);
                    }

                    progressData = new ProgressDialogData(Resources.NuGetUpgrade_WaitMessage, Resources.NuGetUpgrade_Progress_Installing);
                    progress.Report(progressData);
                    var activeSources = new List <SourceRepository>();
                    PackageSourceMoniker
                    .PopulateList(context.SourceProvider)
                    .ForEach(s => activeSources.AddRange(s.SourceRepositories));
                    var packagesToInstall = GetPackagesToInstall(upgradeDependencyItems).ToList();
                    packagesCount = packagesToInstall.Count;

                    // create low level NuGet actions based on number of packages being installed
                    var lowLevelActions = new List <NuGetProjectAction>();
                    foreach (var packageIdentity in packagesToInstall)
                    {
                        lowLevelActions.Add(NuGetProjectAction.CreateInstallProjectAction(packageIdentity, activeSources.FirstOrDefault(), nuGetProject));
                    }

                    try
                    {
                        var buildIntegratedProject = nuGetProject as BuildIntegratedNuGetProject;
                        await context.PackageManager.ExecuteBuildIntegratedProjectActionsAsync(
                            buildIntegratedProject,
                            lowLevelActions,
                            uiService.ProjectContext,
                            token);

                        if (ideExecutionContext != null)
                        {
                            await ideExecutionContext.CollapseAllNodes(solutionManager);
                        }

                        return(backupPath);
                    }
                    catch (Exception ex)
                    {
                        status = NuGetOperationStatus.Failed;

                        uiService.ShowError(ex);
                        uiService.ProjectContext.Log(MessageLevel.Info,
                                                     string.Format(CultureInfo.CurrentCulture, Resources.Upgrade_InstallFailed, backupPath));
                        uiService.ProjectContext.Log(MessageLevel.Info,
                                                     string.Format(CultureInfo.CurrentCulture, Resources.Upgrade_RevertSteps, "https://aka.ms/nugetupgraderevertv1"));

                        return(null);
                    }
                }
                catch (Exception ex)
                {
                    status = NuGetOperationStatus.Failed;
                    uiService.ShowError(ex);
                    return(null);
                }
                finally
                {
                    telemetry.TelemetryEvent = VSTelemetryServiceUtility.GetUpgradeTelemetryEvent(
                        uiService.Projects,
                        status,
                        packagesCount);
                }
            }
        }
示例#3
0
        public async ValueTask <IReadOnlyCollection <IPackageReferenceContextInfo> > GetInstalledPackagesAsync(
            IReadOnlyCollection <string> projectIds,
            CancellationToken cancellationToken)
        {
            Assumes.NotNullOrEmpty(projectIds);

            cancellationToken.ThrowIfCancellationRequested();

            IReadOnlyList <NuGetProject> projects = await GetProjectsAsync(projectIds, cancellationToken);

            List <Task <IEnumerable <PackageReference> > > tasks = projects
                                                                   .Select(project => project.GetInstalledPackagesAsync(cancellationToken))
                                                                   .ToList();

            IEnumerable <PackageReference>[] results = await Task.WhenAll(tasks);

            var installedPackages = new List <PackageReferenceContextInfo>();
            GetInstalledPackagesAsyncTelemetryEvent?telemetryEvent = null;

            for (var i = 0; i < results.Length; ++i)
            {
                IEnumerable <PackageReference> packageReferences = results[i];
                int totalCount = 0;
                int nullCount  = 0;

                foreach (PackageReference?packageReference in packageReferences)
                {
                    ++totalCount;

                    if (packageReference is null)
                    {
                        ++nullCount;

                        continue;
                    }

                    PackageReferenceContextInfo installedPackage = PackageReferenceContextInfo.Create(packageReference);

                    installedPackages.Add(installedPackage);
                }

                if (nullCount > 0)
                {
                    telemetryEvent ??= new GetInstalledPackagesAsyncTelemetryEvent();

                    NuGetProject project = projects[i];

                    string           projectId   = project.GetMetadata <string>(NuGetProjectMetadataKeys.ProjectId);
                    NuGetProjectType projectType = VSTelemetryServiceUtility.GetProjectType(project);

                    telemetryEvent.AddProject(projectType, projectId, nullCount, totalCount);
                }
            }

            if (telemetryEvent is object)
            {
                TelemetryActivity.EmitTelemetryEvent(telemetryEvent);
            }

            return(installedPackages);
        }
        public async Task UpgradeNuGetProjectAsync(INuGetUI uiService, NuGetProject nuGetProject)
        {
            var context = uiService.UIContext;
            // Restore the project before proceeding
            var solutionDirectory = context.SolutionManager.SolutionDirectory;

            await context.PackageRestoreManager.RestoreMissingPackagesInSolutionAsync(
                solutionDirectory,
                uiService.ProjectContext,
                new LoggerAdapter(uiService.ProjectContext),
                CancellationToken.None);

            var packagesDependencyInfo = await context.PackageManager.GetInstalledPackagesDependencyInfo(nuGetProject, CancellationToken.None, includeUnresolved : true);

            var upgradeInformationWindowModel = new NuGetProjectUpgradeWindowModel((MSBuildNuGetProject)nuGetProject, packagesDependencyInfo.ToList());

            var result = uiService.ShowNuGetUpgradeWindow(upgradeInformationWindowModel);

            if (!result)
            {
                // raise upgrade telemetry event with Cancelled status
                var packagesCount = upgradeInformationWindowModel.UpgradeDependencyItems.Count;

                var upgradeTelemetryEvent = VSTelemetryServiceUtility.GetUpgradeTelemetryEvent(
                    uiService.Projects,
                    NuGetOperationStatus.Cancelled,
                    packagesCount);

                TelemetryActivity.EmitTelemetryEvent(upgradeTelemetryEvent);

                return;
            }

            var    progressDialogData = new ProgressDialogData(Resources.NuGetUpgrade_WaitMessage);
            string backupPath;

            var windowTitle = string.Format(
                CultureInfo.CurrentCulture,
                Resources.WindowTitle_NuGetMigrator,
                NuGetProject.GetUniqueNameOrName(nuGetProject));

            using (var progressDialogSession = await context.StartModalProgressDialogAsync(windowTitle, progressDialogData, uiService))
            {
                backupPath = await PackagesConfigToPackageReferenceMigrator.DoUpgradeAsync(
                    context,
                    uiService,
                    nuGetProject,
                    upgradeInformationWindowModel.UpgradeDependencyItems,
                    upgradeInformationWindowModel.NotFoundPackages,
                    progressDialogSession.Progress,
                    progressDialogSession.UserCancellationToken);
            }

            if (!string.IsNullOrEmpty(backupPath))
            {
                var htmlLogFile = GenerateUpgradeReport(nuGetProject, backupPath, upgradeInformationWindowModel);

                Process process = null;
                try
                {
                    process = Process.Start(htmlLogFile);
                }
                catch { }
            }
        }
示例#5
0
        /// <summary>
        /// The internal implementation to perform user action.
        /// </summary>
        /// <param name="resolveActionsAsync">A function that returns a task that resolves the user
        /// action into project actions.</param>
        /// <param name="executeActionsAsync">A function that returns a task that executes
        /// the project actions.</param>
        private async Task PerformActionImplAsync(
            INuGetUI uiService,
            Func <SourceCacheContext, Task <IReadOnlyList <ResolvedAction> > > resolveActionsAsync,
            Func <IReadOnlyList <ResolvedAction>, SourceCacheContext, Task> executeActionsAsync,
            NuGetOperationType operationType,
            CancellationToken token)
        {
            var status       = NuGetOperationStatus.Succeeded;
            var startTime    = DateTimeOffset.Now;
            var packageCount = 0;

            // Enable granular level telemetry events for nuget ui operation
            uiService.ProjectContext.OperationId = Guid.NewGuid();

            await _lockService.ExecuteNuGetOperationAsync(async() =>
            {
                try
                {
                    uiService.BeginOperation();

                    var acceptedFormat = await CheckPackageManagementFormat(uiService, token);
                    if (!acceptedFormat)
                    {
                        return;
                    }

                    TelemetryServiceUtility.StartOrResumeTimer();

                    using (var sourceCacheContext = new SourceCacheContext())
                    {
                        var actions = await resolveActionsAsync(sourceCacheContext);
                        var results = GetPreviewResults(actions);

                        if (operationType == NuGetOperationType.Uninstall)
                        {
                            packageCount = results.SelectMany(result => result.Deleted).
                                           Select(package => package.Id).Distinct().Count();
                        }
                        else
                        {
                            var addCount = results.SelectMany(result => result.Added).
                                           Select(package => package.Id).Distinct().Count();

                            var updateCount = results.SelectMany(result => result.Updated).
                                              Select(result => result.New.Id).Distinct().Count();

                            // update packages count
                            packageCount = addCount + updateCount;

                            if (updateCount > 0)
                            {
                                // set operation type to update when there are packages being updated
                                operationType = NuGetOperationType.Update;
                            }
                        }

                        TelemetryServiceUtility.StopTimer();

                        // Show the preview window.
                        if (uiService.DisplayPreviewWindow)
                        {
                            var shouldContinue = uiService.PromptForPreviewAcceptance(results);
                            if (!shouldContinue)
                            {
                                return;
                            }
                        }

                        TelemetryServiceUtility.StartOrResumeTimer();

                        // Show the license acceptance window.
                        var accepted = await CheckLicenseAcceptanceAsync(uiService, results, token);

                        TelemetryServiceUtility.StartOrResumeTimer();

                        if (!accepted)
                        {
                            return;
                        }

                        // Warn about the fact that the "dotnet" TFM is deprecated.
                        if (uiService.DisplayDeprecatedFrameworkWindow)
                        {
                            var shouldContinue = ShouldContinueDueToDotnetDeprecation(uiService, actions, token);

                            TelemetryServiceUtility.StartOrResumeTimer();

                            if (!shouldContinue)
                            {
                                return;
                            }
                        }

                        if (!token.IsCancellationRequested)
                        {
                            // execute the actions
                            await executeActionsAsync(actions, sourceCacheContext);

                            // fires ActionsExecuted event to update the UI
                            uiService.OnActionsExecuted(actions);
                        }
                    }
                }
                catch (System.Net.Http.HttpRequestException ex)
                {
                    status = NuGetOperationStatus.Failed;
                    if (ex.InnerException != null)
                    {
                        uiService.ShowError(ex.InnerException);
                    }
                    else
                    {
                        uiService.ShowError(ex);
                    }
                }
                catch (Exception ex)
                {
                    status = NuGetOperationStatus.Failed;
                    uiService.ShowError(ex);
                }
                finally
                {
                    TelemetryServiceUtility.StopTimer();

                    var duration = TelemetryServiceUtility.GetTimerElapsedTime();

                    uiService.ProjectContext.Log(MessageLevel.Info,
                                                 string.Format(CultureInfo.CurrentCulture, Resources.Operation_TotalTime, duration));

                    uiService.EndOperation();

                    var actionTelemetryEvent = VSTelemetryServiceUtility.GetActionTelemetryEvent(
                        uiService.ProjectContext.OperationId.ToString(),
                        uiService.Projects,
                        operationType,
                        OperationSource.UI,
                        startTime,
                        status,
                        packageCount,
                        duration.TotalSeconds);

                    TelemetryActivity.EmitTelemetryEvent(actionTelemetryEvent);
                }
            }, token);
        }
示例#6
0
        private async Task PerformActionImplAsync(
            IServiceBroker serviceBroker,
            INuGetProjectManagerService projectManagerService,
            INuGetUI uiService,
            ResolveActionsAsync resolveActionsAsync,
            NuGetOperationType operationType,
            UserAction userAction,
            CancellationToken cancellationToken)
        {
            var status       = NuGetOperationStatus.Succeeded;
            var startTime    = DateTimeOffset.Now;
            var packageCount = 0;

            var continueAfterPreview = true;
            var acceptedLicense      = true;

            List <string> removedPackages  = null;
            var           existingPackages = new HashSet <Tuple <string, string> >();
            List <Tuple <string, string> > addedPackages      = null;
            List <Tuple <string, string> > updatedPackagesOld = null;
            List <Tuple <string, string> > updatedPackagesNew = null;
            bool?packageToInstallWasTransitive = null;

            // Enable granular level telemetry events for nuget ui operation
            uiService.ProjectContext.OperationId = Guid.NewGuid();

            Stopwatch packageEnumerationTime = new Stopwatch();

            packageEnumerationTime.Start();
            try
            {
                IServiceBroker sb            = uiService.UIContext.ServiceBroker;
                int            projectsCount = uiService.Projects.Count();
                IEnumerable <IPackageReferenceContextInfo> installedPackages = null;
                // collect the install state of the existing packages
                foreach (IProjectContextInfo project in uiService.Projects) // only one project when PM UI is in project mode
                {
                    if (projectsCount == 1 && !userAction.IsSolutionLevel && userAction.Action == NuGetProjectActionType.Install && project.ProjectStyle == ProjectModel.ProjectStyle.PackageReference && project.ProjectKind == NuGetProjectKind.PackageReference)
                    {
                        IInstalledAndTransitivePackages installedAndTransitives = await project.GetInstalledAndTransitivePackagesAsync(sb, cancellationToken);

                        installedPackages = installedAndTransitives.InstalledPackages;

                        packageToInstallWasTransitive = false;
                        string packageIdToInstall = VSTelemetryServiceUtility.NormalizePackageId(userAction.PackageId);
                        foreach (IPackageReferenceContextInfo transitivePackage in installedAndTransitives.TransitivePackages)
                        {
                            if (packageIdToInstall == VSTelemetryServiceUtility.NormalizePackageId(transitivePackage.Identity.Id))
                            {
                                packageToInstallWasTransitive = true;
                                break;
                            }
                        }
                    }
                    else
                    {
                        installedPackages = await project.GetInstalledPackagesAsync(sb, cancellationToken);
                    }

                    foreach (IPackageReferenceContextInfo package in installedPackages)
                    {
                        existingPackages.Add(CreatePackageTuple(package));
                    }
                }
            }
            catch (Exception)
            {
                // don't teardown the process if we have a telemetry failure
            }
            packageEnumerationTime.Stop();

            await _lockService.ExecuteNuGetOperationAsync(async() =>
            {
                try
                {
                    uiService.BeginOperation();

                    using (INuGetProjectUpgraderService projectUpgrader = await serviceBroker.GetProxyAsync <INuGetProjectUpgraderService>(
                               NuGetServices.ProjectUpgraderService,
                               cancellationToken))
                    {
                        bool isAcceptedFormat = await CheckPackageManagementFormatAsync(projectUpgrader, uiService, cancellationToken);
                        if (!isAcceptedFormat)
                        {
                            return;
                        }
                    }

                    TelemetryServiceUtility.StartOrResumeTimer();

                    IReadOnlyList <ProjectAction> actions = await resolveActionsAsync(projectManagerService);
                    IReadOnlyList <PreviewResult> results = await GetPreviewResultsAsync(projectManagerService, actions, cancellationToken);

                    if (operationType == NuGetOperationType.Uninstall)
                    {
                        // removed packages don't have version info
                        removedPackages = results.SelectMany(result => result.Deleted)
                                          .Select(package => package.Id)
                                          .Distinct()
                                          .ToList();
                        packageCount = removedPackages.Count;
                    }
                    else
                    {
                        // log rich info about added packages
                        addedPackages = results.SelectMany(result => result.Added)
                                        .Select(package => new Tuple <string, string>(package.Id, (package.Version == null ? "" : package.Version.ToNormalizedString())))
                                        .Distinct()
                                        .ToList();
                        var addCount = addedPackages.Count;

                        //updated packages can have an old and a new id.
                        updatedPackagesOld = results.SelectMany(result => result.Updated)
                                             .Select(package => new Tuple <string, string>(package.Old.Id, (package.Old.Version == null ? "" : package.Old.Version.ToNormalizedString())))
                                             .Distinct()
                                             .ToList();
                        updatedPackagesNew = results.SelectMany(result => result.Updated)
                                             .Select(package => new Tuple <string, string>(package.New.Id, (package.New.Version == null ? "" : package.New.Version.ToNormalizedString())))
                                             .Distinct()
                                             .ToList();
                        var updateCount = updatedPackagesNew.Count;

                        // update packages count
                        packageCount = addCount + updateCount;

                        if (updateCount > 0)
                        {
                            // set operation type to update when there are packages being updated
                            operationType = NuGetOperationType.Update;
                        }
                    }

                    TelemetryServiceUtility.StopTimer();

                    // Show the preview window.
                    if (uiService.DisplayPreviewWindow)
                    {
                        bool shouldContinue = uiService.PromptForPreviewAcceptance(results);
                        if (!shouldContinue)
                        {
                            continueAfterPreview = false;
                            return;
                        }
                    }

                    TelemetryServiceUtility.StartOrResumeTimer();

                    // Show the license acceptance window.
                    bool accepted = await CheckLicenseAcceptanceAsync(uiService, results, cancellationToken);

                    TelemetryServiceUtility.StartOrResumeTimer();

                    if (!accepted)
                    {
                        acceptedLicense = false;
                        return;
                    }

                    // Warn about the fact that the "dotnet" TFM is deprecated.
                    if (uiService.DisplayDeprecatedFrameworkWindow)
                    {
                        bool shouldContinue = await ShouldContinueDueToDotnetDeprecationAsync(projectManagerService, uiService, cancellationToken);

                        TelemetryServiceUtility.StartOrResumeTimer();

                        if (!shouldContinue)
                        {
                            return;
                        }
                    }

                    if (!cancellationToken.IsCancellationRequested)
                    {
                        await projectManagerService.ExecuteActionsAsync(
                            actions,
                            cancellationToken);

                        string[] projectIds = actions
                                              .Select(action => action.ProjectId)
                                              .Distinct()
                                              .ToArray();

                        uiService.UIContext.RaiseProjectActionsExecuted(projectIds);
                    }
                    else
                    {
                        status = NuGetOperationStatus.Cancelled;
                    }
                }
                catch (System.Net.Http.HttpRequestException ex)
                {
                    status = NuGetOperationStatus.Failed;
                    if (ex.InnerException != null)
                    {
                        uiService.ShowError(ex.InnerException);
                    }
                    else
                    {
                        uiService.ShowError(ex);
                    }
                }
                catch (Exception ex)
                {
                    status = NuGetOperationStatus.Failed;
                    uiService.ShowError(ex);
                }
                finally
                {
                    TelemetryServiceUtility.StopTimer();

                    var duration = TelemetryServiceUtility.GetTimerElapsedTime();

                    uiService.ProjectContext.Log(MessageLevel.Info,
                                                 string.Format(CultureInfo.CurrentCulture, Resources.Operation_TotalTime, duration));

                    uiService.EndOperation();

                    // don't show "Succeeded" if we actually cancelled...
                    if ((!continueAfterPreview) || (!acceptedLicense))
                    {
                        if (status == NuGetOperationStatus.Succeeded)
                        {
                            status = NuGetOperationStatus.Cancelled;
                        }
                    }

                    var plc = new PackageLoadContext(isSolution: false, uiService.UIContext);
                    IReadOnlyCollection <string> frameworks = await plc.GetSupportedFrameworksAsync();
                    string[] projectIds = (await ProjectUtility.GetSortedProjectIdsAsync(
                                               uiService.UIContext.ServiceBroker,
                                               uiService.Projects,
                                               cancellationToken)).ToArray();

                    var packageSourceMapping           = PackageSourceMapping.GetPackageSourceMapping(uiService.Settings);
                    bool isPackageSourceMappingEnabled = packageSourceMapping?.IsEnabled ?? false;
                    var actionTelemetryEvent           = new VSActionsTelemetryEvent(
                        uiService.ProjectContext.OperationId.ToString(),
                        projectIds,
                        operationType,
                        OperationSource.UI,
                        startTime,
                        status,
                        packageCount,
                        DateTimeOffset.Now,
                        duration.TotalSeconds,
                        isPackageSourceMappingEnabled: isPackageSourceMappingEnabled);

                    var nuGetUI = uiService as NuGetUI;
                    AddUiActionEngineTelemetryProperties(
                        actionTelemetryEvent,
                        continueAfterPreview,
                        acceptedLicense,
                        userAction,
                        nuGetUI?.SelectedIndex,
                        nuGetUI?.RecommendedCount,
                        nuGetUI?.RecommendPackages,
                        nuGetUI?.RecommenderVersion,
                        nuGetUI?.TopLevelVulnerablePackagesCount ?? 0,
                        nuGetUI?.TopLevelVulnerablePackagesMaxSeverities?.ToList() ?? new List <int>(),
                        existingPackages,
                        addedPackages,
                        removedPackages,
                        updatedPackagesOld,
                        updatedPackagesNew,
                        frameworks);

                    if (packageToInstallWasTransitive.HasValue)
                    {
                        actionTelemetryEvent.PackageToInstallWasTransitive = packageToInstallWasTransitive.Value;
                    }
                    actionTelemetryEvent["InstalledPackageEnumerationTimeInMilliseconds"] = packageEnumerationTime.ElapsedMilliseconds;

                    TelemetryActivity.EmitTelemetryEvent(actionTelemetryEvent);
                }
            }, cancellationToken);
        }
        public void HyperlinkClicked_CorrelatesSearchSelectionAndAction_Succeeds()
        {
            // Arrange
            var            telemetrySession   = new Mock <ITelemetrySession>();
            TelemetryEvent lastTelemetryEvent = null;

            _ = telemetrySession
                .Setup(x => x.PostEvent(It.IsAny <TelemetryEvent>()))
                .Callback <TelemetryEvent>(x => lastTelemetryEvent = x);

            var service = new NuGetVSTelemetryService(telemetrySession.Object);

            var testPackageId      = "testPackage.id";
            var testPackageVersion = new NuGetVersion(1, 0, 0);

            var evtHyperlink = new HyperlinkClickedTelemetryEvent(
                HyperlinkType.DeprecationAlternativeDetails,
                ContractsItemFilter.All,
                isSolutionView: false,
                testPackageId);

            var evtSearch = new SearchSelectionTelemetryEvent(
                parentId: It.IsAny <Guid>(),
                recommendedCount: It.IsAny <int>(),
                itemIndex: It.IsAny <int>(),
                packageId: testPackageId,
                packageVersion: testPackageVersion,
                isPackageVulnerable: It.IsAny <bool>(),
                isPackageDeprecated: true,
                hasDeprecationAlternativePackage: true);

            var evtActions = new VSActionsTelemetryEvent(
                operationId: It.IsAny <string>(),
                projectIds: new[] { Guid.NewGuid().ToString() },
                operationType: NuGetOperationType.Install,
                source: OperationSource.PMC,
                startTime: DateTimeOffset.Now.AddSeconds(-1),
                status: NuGetOperationStatus.NoOp,
                packageCount: 1,
                endTime: DateTimeOffset.Now,
                duration: .40,
                isPackageSourceMappingEnabled: false);

            // Simulate UIActionEngine.AddUiActionEngineTelemetryProperties()
            var pkgAdded = new TelemetryEvent(eventName: null);

            pkgAdded.AddPiiData("id", VSTelemetryServiceUtility.NormalizePackageId(testPackageId));
            pkgAdded.AddPiiData("version", testPackageVersion.ToNormalizedString());

            var packages = new List <TelemetryEvent>
            {
                pkgAdded
            };

            evtActions.ComplexData["AddedPackages"] = packages;

            // Act
            service.EmitTelemetryEvent(evtHyperlink);
            var hyperlinkEmitted = lastTelemetryEvent;

            service.EmitTelemetryEvent(evtSearch);
            var searchEmitted = lastTelemetryEvent;

            service.EmitTelemetryEvent(evtActions);
            var actionEmitted = lastTelemetryEvent;

            // Assert
            var packageIdHyperlink = hyperlinkEmitted.GetPiiData().First(x => x.Key == HyperlinkClickedTelemetryEvent.AlternativePackageIdPropertyName).Value;
            var packageIdSearch    = searchEmitted.GetPiiData().First(x => x.Key == "PackageId").Value;
            var packageIdsAction   = (IEnumerable <TelemetryEvent>)actionEmitted.ComplexData["AddedPackages"];
            var packageIds         = packageIdsAction.Select(x => x.GetPiiData().First(x => x.Key == "id").Value);

            Assert.Equal(packageIdHyperlink, packageIdSearch);
            Assert.Contains(packageIdHyperlink, packageIds);
        }