Skip to content
This repository was archived by the owner on Apr 20, 2023. It is now read-only.

Commit 20f0dac

Browse files
committed
Making a change that will cause the first run notice to always show up in the first run of the CLI, even when it is installed by native installers.
1 parent 5d07534 commit 20f0dac

File tree

7 files changed

+191
-13
lines changed

7 files changed

+191
-13
lines changed

src/Microsoft.DotNet.Configurer/DotnetFirstTimeUseConfigurer.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,12 @@ public void Configure()
4545
{
4646
PrintUnauthorizedAccessMessage();
4747
}
48+
else
49+
{
50+
PrintNugetCachePrimeMessage();
4851

49-
PrintNugetCachePrimeMessage();
50-
51-
_nugetCachePrimer.PrimeCache();
52+
_nugetCachePrimer.PrimeCache();
53+
}
5254
}
5355
}
5456

@@ -81,6 +83,8 @@ private void PrintUnauthorizedAccessMessage()
8183
private bool ShouldPrimeNugetCache()
8284
{
8385
return ShouldRunFirstRunExperience() &&
86+
!_nugetCacheSentinel.Exists() &&
87+
!_nugetCacheSentinel.InProgressSentinelAlreadyExists() &&
8488
!_nugetCachePrimer.SkipPrimingTheCache();
8589
}
8690

@@ -96,9 +100,7 @@ private bool ShouldRunFirstRunExperience()
96100
var skipFirstTimeExperience =
97101
_environmentProvider.GetEnvironmentVariableAsBool("DOTNET_SKIP_FIRST_TIME_EXPERIENCE", false);
98102

99-
return !skipFirstTimeExperience &&
100-
!_nugetCacheSentinel.Exists() &&
101-
!_nugetCacheSentinel.InProgressSentinelAlreadyExists();
103+
return !skipFirstTimeExperience;
102104
}
103105
}
104106
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.IO;
5+
using Microsoft.DotNet.Cli.Utils;
6+
using Microsoft.Extensions.EnvironmentAbstractions;
7+
using NuGet.Configuration;
8+
9+
namespace Microsoft.DotNet.Configurer
10+
{
11+
public class NoOpFirstTimeUseNoticeSentinel : IFirstTimeUseNoticeSentinel
12+
{
13+
public bool Exists()
14+
{
15+
return true;
16+
}
17+
18+
public void CreateIfNotExists()
19+
{
20+
}
21+
22+
public void Dispose()
23+
{
24+
}
25+
}
26+
}

src/Microsoft.DotNet.Configurer/NuGetCacheSentinel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ internal NuGetCacheSentinel(string nugetCachePath, IFile file, IDirectory direct
4545

4646
public bool InProgressSentinelAlreadyExists()
4747
{
48-
return CouldNotGetAHandleToTheInProgressSentinel();
48+
return CouldNotGetAHandleToTheInProgressSentinel() && !UnauthorizedAccess;
4949
}
5050

5151
public bool Exists()

src/dotnet/Program.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,10 @@ internal static int ProcessArgs(string[] args, ITelemetry telemetryClient = null
8181
var lastArg = 0;
8282
var cliFallbackFolderPathCalculator = new CliFallbackFolderPathCalculator();
8383
using (INuGetCacheSentinel nugetCacheSentinel = new NuGetCacheSentinel(cliFallbackFolderPathCalculator))
84-
using (IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel = new FirstTimeUseNoticeSentinel(cliFallbackFolderPathCalculator))
84+
using (IFirstTimeUseNoticeSentinel disposableFirstTimeUseNoticeSentinel =
85+
new FirstTimeUseNoticeSentinel(cliFallbackFolderPathCalculator))
8586
{
87+
IFirstTimeUseNoticeSentinel firstTimeUseNoticeSentinel = disposableFirstTimeUseNoticeSentinel;
8688
for (; lastArg < args.Length; lastArg++)
8789
{
8890
if (IsArg(args[lastArg], "d", "diagnostics"))
@@ -113,10 +115,19 @@ internal static int ProcessArgs(string[] args, ITelemetry telemetryClient = null
113115
}
114116
else
115117
{
116-
ConfigureDotNetForFirstTimeUse(nugetCacheSentinel, firstTimeUseNoticeSentinel, cliFallbackFolderPathCalculator);
117-
118118
// It's the command, and we're done!
119119
command = args[lastArg];
120+
121+
if (IsDotnetBeingInvokedFromNativeInstaller(command))
122+
{
123+
firstTimeUseNoticeSentinel = new NoOpFirstTimeUseNoticeSentinel();
124+
}
125+
126+
ConfigureDotNetForFirstTimeUse(
127+
nugetCacheSentinel,
128+
firstTimeUseNoticeSentinel,
129+
cliFallbackFolderPathCalculator);
130+
120131
break;
121132
}
122133
}
@@ -164,7 +175,11 @@ internal static int ProcessArgs(string[] args, ITelemetry telemetryClient = null
164175
}
165176

166177
return exitCode;
178+
}
167179

180+
private static bool IsDotnetBeingInvokedFromNativeInstaller(string command)
181+
{
182+
return command == "internal-reportinstallsuccess";
168183
}
169184

170185
private static void ConfigureDotNetForFirstTimeUse(

test/Microsoft.DotNet.Configurer.UnitTests/GivenADotnetFirstTimeUseConfigurer.cs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,5 +233,73 @@ public void It_prints_first_use_notice_and_primes_the_cache_if_the_sentinels_do_
233233
_nugetCachePrimerMock.Verify(r => r.PrimeCache(), Times.Once);
234234
_reporterMock.Verify(r => r.Write(It.IsAny<string>()), Times.Never);
235235
}
236+
237+
[Fact]
238+
public void It_prints_the_first_time_use_notice_if_the_cache_sentinel_exists_but_the_first_notice_sentinel_does_not()
239+
{
240+
_nugetCacheSentinelMock.Setup(n => n.Exists()).Returns(true);
241+
_firstTimeUseNoticeSentinelMock.Setup(n => n.Exists()).Returns(false);
242+
243+
var dotnetFirstTimeUseConfigurer = new DotnetFirstTimeUseConfigurer(
244+
_nugetCachePrimerMock.Object,
245+
_nugetCacheSentinelMock.Object,
246+
_firstTimeUseNoticeSentinelMock.Object,
247+
_environmentProviderMock.Object,
248+
_reporterMock.Object,
249+
CliFallbackFolderPath);
250+
251+
dotnetFirstTimeUseConfigurer.Configure();
252+
253+
_reporterMock.Verify(r =>
254+
r.WriteLine(It.Is<string>(str => str == LocalizableStrings.FirstTimeWelcomeMessage)));
255+
_reporterMock.Verify(
256+
r => r.WriteLine(It.Is<string>(str => str == LocalizableStrings.NugetCachePrimeMessage)),
257+
Times.Never);
258+
_reporterMock.Verify(r => r.Write(It.IsAny<string>()), Times.Never);
259+
}
260+
261+
[Fact]
262+
public void It_prints_the_unauthorized_notice_if_the_cache_sentinel_reports_Unauthorized()
263+
{
264+
_nugetCacheSentinelMock.Setup(n => n.UnauthorizedAccess).Returns(true);
265+
266+
var dotnetFirstTimeUseConfigurer = new DotnetFirstTimeUseConfigurer(
267+
_nugetCachePrimerMock.Object,
268+
_nugetCacheSentinelMock.Object,
269+
_firstTimeUseNoticeSentinelMock.Object,
270+
_environmentProviderMock.Object,
271+
_reporterMock.Object,
272+
CliFallbackFolderPath);
273+
274+
dotnetFirstTimeUseConfigurer.Configure();
275+
276+
_reporterMock.Verify(r =>
277+
r.WriteLine(It.Is<string>(str => str == LocalizableStrings.FirstTimeWelcomeMessage)));
278+
_reporterMock.Verify(r =>
279+
r.WriteLine(It.Is<string>(str =>
280+
str == string.Format(LocalizableStrings.UnauthorizedAccessMessage, CliFallbackFolderPath))));
281+
_reporterMock.Verify(
282+
r => r.WriteLine(It.Is<string>(str => str == LocalizableStrings.NugetCachePrimeMessage)),
283+
Times.Never);
284+
_reporterMock.Verify(r => r.Write(It.IsAny<string>()), Times.Never);
285+
}
286+
287+
[Fact]
288+
public void It_does_not_prime_the_cache_if_the_cache_sentinel_reports_Unauthorized()
289+
{
290+
_nugetCacheSentinelMock.Setup(n => n.UnauthorizedAccess).Returns(true);
291+
292+
var dotnetFirstTimeUseConfigurer = new DotnetFirstTimeUseConfigurer(
293+
_nugetCachePrimerMock.Object,
294+
_nugetCacheSentinelMock.Object,
295+
_firstTimeUseNoticeSentinelMock.Object,
296+
_environmentProviderMock.Object,
297+
_reporterMock.Object,
298+
CliFallbackFolderPath);
299+
300+
dotnetFirstTimeUseConfigurer.Configure();
301+
302+
_nugetCachePrimerMock.Verify(r => r.PrimeCache(), Times.Never);
303+
}
236304
}
237305
}

test/Microsoft.DotNet.Configurer.UnitTests/GivenANuGetCacheSentinel.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@ public void It_returns_true_to_the_in_progress_sentinel_already_exists_when_it_f
7070
nugetCacheSentinel.InProgressSentinelAlreadyExists().Should().BeTrue();
7171
}
7272

73+
[Fact]
74+
public void It_returns_false_to_the_in_progress_sentinel_already_exists_when_it_fails_to_get_a_handle_to_it_but_it_failed_because_it_was_unauthorized()
75+
{
76+
var fileMock = new FileMock();
77+
var directoryMock = new DirectoryMock();
78+
fileMock.InProgressSentinel = null;
79+
var nugetCacheSentinel =
80+
new NuGetCacheSentinel(NUGET_CACHE_PATH, fileMock, directoryMock);
81+
82+
nugetCacheSentinel.InProgressSentinelAlreadyExists().Should().BeFalse();
83+
}
84+
7385
[Fact]
7486
public void It_returns_false_to_the_in_progress_sentinel_already_exists_when_it_succeeds_in_getting_a_handle_to_it()
7587
{

test/dotnet.Tests/GivenThatTheUserIsRunningDotNetForTheFirstTime.cs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,17 @@ public class GivenThatTheUserIsRunningDotNetForTheFirstTime : TestBase
2020
private static CommandResult _firstDotnetNonVerbUseCommandResult;
2121
private static CommandResult _firstDotnetVerbUseCommandResult;
2222
private static DirectoryInfo _nugetFallbackFolder;
23+
private static DirectoryInfo _dotDotnetFolder;
24+
private static string _testDirectory;
2325

2426
static GivenThatTheUserIsRunningDotNetForTheFirstTime()
2527
{
26-
var testDirectory = TestAssets.CreateTestDirectory("Dotnet_first_time_experience_tests");
27-
var testNuGetHome = Path.Combine(testDirectory.FullName, "nuget_home");
28+
_testDirectory = TestAssets.CreateTestDirectory("Dotnet_first_time_experience_tests").FullName;
29+
var testNuGetHome = Path.Combine(_testDirectory, "nuget_home");
2830
var cliTestFallbackFolder = Path.Combine(testNuGetHome, ".dotnet", "NuGetFallbackFolder");
2931

3032
var command = new DotnetCommand()
31-
.WithWorkingDirectory(testDirectory);
33+
.WithWorkingDirectory(_testDirectory);
3234
command.Environment["HOME"] = testNuGetHome;
3335
command.Environment["USERPROFILE"] = testNuGetHome;
3436
command.Environment["APPDATA"] = testNuGetHome;
@@ -40,6 +42,7 @@ static GivenThatTheUserIsRunningDotNetForTheFirstTime()
4042
_firstDotnetVerbUseCommandResult = command.ExecuteWithCapturedOutput("new --debug:ephemeral-hive");
4143

4244
_nugetFallbackFolder = new DirectoryInfo(cliTestFallbackFolder);
45+
_dotDotnetFolder = new DirectoryInfo(Path.Combine(testNuGetHome, ".dotnet"));
4346
}
4447

4548
[Fact]
@@ -77,6 +80,58 @@ public void ItCreatesASentinelFileUnderTheNuGetCacheFolder()
7780
.HaveFile($"{GetDotnetVersion()}.dotnetSentinel");
7881
}
7982

83+
[Fact]
84+
public void ItCreatesAFirstUseSentinelFileUnderTheDotDotNetFolder()
85+
{
86+
_dotDotnetFolder
87+
.Should()
88+
.HaveFile($"{GetDotnetVersion()}.dotnetFirstUseSentinel");
89+
}
90+
91+
[Fact]
92+
public void ItDoesNotCreateAFirstUseSentinelFileUnderTheDotDotNetFolderWhenInternalReportInstallSuccessIsInvoked()
93+
{
94+
var newHome = Path.Combine(_testDirectory, "new_home");
95+
var newHomeFolder = new DirectoryInfo(Path.Combine(newHome, ".dotnet"));
96+
97+
var command = new DotnetCommand()
98+
.WithWorkingDirectory(_testDirectory);
99+
command.Environment["HOME"] = newHome;
100+
command.Environment["USERPROFILE"] = newHome;
101+
command.Environment["APPDATA"] = newHome;
102+
command.Environment["DOTNET_CLI_TEST_FALLBACKFOLDER"] = _nugetFallbackFolder.FullName;
103+
command.Environment["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "";
104+
command.Environment["SkipInvalidConfigurations"] = "true";
105+
106+
command.ExecuteWithCapturedOutput("internal-reportinstallsuccess test").Should().Pass();
107+
108+
newHomeFolder.Should().NotHaveFile($"{GetDotnetVersion()}.dotnetFirstUseSentinel");
109+
}
110+
111+
[Fact]
112+
public void ItShowsTheTelemetryNoticeWhenInvokingACommandAfterInternalReportInstallSuccessHasBeenInvoked()
113+
{
114+
var newHome = Path.Combine(_testDirectory, "new_home");
115+
var newHomeFolder = new DirectoryInfo(Path.Combine(newHome, ".dotnet"));
116+
117+
var command = new DotnetCommand()
118+
.WithWorkingDirectory(_testDirectory);
119+
command.Environment["HOME"] = newHome;
120+
command.Environment["USERPROFILE"] = newHome;
121+
command.Environment["APPDATA"] = newHome;
122+
command.Environment["DOTNET_CLI_TEST_FALLBACKFOLDER"] = _nugetFallbackFolder.FullName;
123+
command.Environment["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "";
124+
command.Environment["SkipInvalidConfigurations"] = "true";
125+
126+
command.ExecuteWithCapturedOutput("internal-reportinstallsuccess test").Should().Pass();
127+
128+
var result = command.ExecuteWithCapturedOutput("new --debug:ephemeral-hive");
129+
130+
result.StdOut
131+
.Should()
132+
.ContainVisuallySameFragment(Configurer.LocalizableStrings.FirstTimeWelcomeMessage);
133+
}
134+
80135
[Fact]
81136
public void ItRestoresTheNuGetPackagesToTheNuGetCacheFolder()
82137
{

0 commit comments

Comments
 (0)