-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Implicitly set UserSecretsId for file-based apps #50783
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
3f4203a
16d7e59
98a7327
9cd2089
5c9429b
348f3b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Text.RegularExpressions; | ||
| using Microsoft.CodeAnalysis.Text; | ||
| using Microsoft.DotNet.Cli.Commands; | ||
| using Microsoft.DotNet.Cli.Commands.Run; | ||
|
|
@@ -56,9 +57,11 @@ public void SameAsTemplate() | |
| var dotnetProjectConvertProjectText = File.ReadAllText(dotnetProjectConvertProject); | ||
| var dotnetNewConsoleProjectText = File.ReadAllText(dotnetNewConsoleProject); | ||
|
|
||
| // There are some differences: we add PublishAot=true. | ||
| // There are some differences: we add PublishAot=true and UserSecretsId. | ||
| var patchedDotnetProjectConvertProjectText = dotnetProjectConvertProjectText | ||
| .Replace(" <PublishAot>true</PublishAot>" + Environment.NewLine, string.Empty); | ||
| patchedDotnetProjectConvertProjectText = Regex.Replace(patchedDotnetProjectConvertProjectText, | ||
| """ <UserSecretsId>[^<]*<\/UserSecretsId>""" + Environment.NewLine, string.Empty); | ||
|
|
||
| patchedDotnetProjectConvertProjectText.Should().Be(dotnetNewConsoleProjectText) | ||
| .And.StartWith("""<Project Sdk="Microsoft.NET.Sdk">"""); | ||
|
|
@@ -648,7 +651,7 @@ public void ProcessingSucceeds() | |
| .Should().Be("Console.WriteLine();"); | ||
|
|
||
| File.ReadAllText(Path.Join(testInstance.Path, "Program", "Program.csproj")) | ||
| .Should().Be($""" | ||
| .Should().Match($""" | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
|
|
@@ -657,6 +660,7 @@ public void ProcessingSucceeds() | |
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| <PublishAot>true</PublishAot> | ||
| <UserSecretsId>Program-*</UserSecretsId> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
|
|
@@ -668,6 +672,87 @@ public void ProcessingSucceeds() | |
| """); | ||
| } | ||
|
|
||
| [Theory, CombinatorialData] | ||
| public void UserSecretsId_Overridden_ViaDirective(bool hasDirectiveBuildProps) | ||
| { | ||
| var testInstance = _testAssetsManager.CreateTestDirectory(); | ||
| File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ | ||
| #:property UserSecretsId=MyIdFromDirective | ||
| Console.WriteLine(); | ||
| """); | ||
|
|
||
| if (hasDirectiveBuildProps) | ||
| { | ||
| File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ | ||
| <Project> | ||
| <PropertyGroup> | ||
| <UserSecretsId>MyIdFromDirBuildProps</UserSecretsId> | ||
| </PropertyGroup> | ||
| </Project> | ||
| """); | ||
| } | ||
|
|
||
| new DotnetCommand(Log, "project", "convert", "Program.cs") | ||
| .WithWorkingDirectory(testInstance.Path) | ||
| .Execute() | ||
| .Should().Pass(); | ||
|
|
||
| File.ReadAllText(Path.Join(testInstance.Path, "Program", "Program.csproj")) | ||
| .Should().Be($""" | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>{ToolsetInfo.CurrentTargetFramework}</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| <PublishAot>true</PublishAot> | ||
| <UserSecretsId>MyIdFromDirective</UserSecretsId> | ||
| </PropertyGroup> | ||
|
|
||
| </Project> | ||
|
|
||
| """); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void UserSecretsId_Overridden_ViaDirectoryBuildProps() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The following are corner cases, but it may be worthwhile to test them, just so we know the behavior.
|
||
| { | ||
| var testInstance = _testAssetsManager.CreateTestDirectory(); | ||
|
|
||
| File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ | ||
| Console.WriteLine(); | ||
| """); | ||
| File.WriteAllText(Path.Join(testInstance.Path, "Directory.Build.props"), """ | ||
| <Project> | ||
| <PropertyGroup> | ||
| <UserSecretsId>MyIdFromDirBuildProps</UserSecretsId> | ||
| </PropertyGroup> | ||
| </Project> | ||
| """); | ||
|
|
||
| new DotnetCommand(Log, "project", "convert", "Program.cs") | ||
| .WithWorkingDirectory(testInstance.Path) | ||
| .Execute() | ||
| .Should().Pass(); | ||
|
|
||
| File.ReadAllText(Path.Join(testInstance.Path, "Program", "Program.csproj")) | ||
| .Should().Be($""" | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>{ToolsetInfo.CurrentTargetFramework}</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| <PublishAot>true</PublishAot> | ||
| </PropertyGroup> | ||
|
|
||
| </Project> | ||
|
|
||
| """); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void Directives() | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2177,6 +2177,70 @@ public void ProjectReference_Errors() | |
| string.Format(CliStrings.MoreThanOneProjectInDirectory, Path.Join(testInstance.Path, "dir/")))); | ||
| } | ||
|
|
||
| [Theory] // https://github.com/dotnet/aspnetcore/issues/63440 | ||
| [InlineData(true, null)] | ||
| [InlineData(false, null, Skip = "Needs https://github.com/dotnet/aspnetcore/pull/63496")] | ||
| [InlineData(true, "test-id")] | ||
| [InlineData(false, "test-id", Skip = "Needs https://github.com/dotnet/aspnetcore/pull/63496")] | ||
| public void UserSecrets(bool useIdArg, string? userSecretsId) | ||
| { | ||
| var testInstance = _testAssetsManager.CreateTestDirectory(); | ||
|
|
||
| string code = $""" | ||
| #:package Microsoft.Extensions.Configuration.UserSecrets@*-* | ||
|
||
| {(userSecretsId is null ? "" : $"#:property UserSecretsId={userSecretsId}")} | ||
|
|
||
| using Microsoft.Extensions.Configuration; | ||
|
|
||
| IConfigurationRoot config = new ConfigurationBuilder() | ||
| .AddUserSecrets<Program>() | ||
| .Build(); | ||
|
|
||
| Console.WriteLine("v1"); | ||
| Console.WriteLine(config.GetDebugView()); | ||
| """; | ||
|
|
||
| var programPath = Path.Join(testInstance.Path, "Program.cs"); | ||
| File.WriteAllText(programPath, code); | ||
|
|
||
| if (useIdArg) | ||
| { | ||
| if (userSecretsId == null) | ||
| { | ||
| var result = new DotnetCommand(Log, "build", "-getProperty:UserSecretsId", "Program.cs") | ||
| .WithWorkingDirectory(testInstance.Path) | ||
| .Execute(); | ||
| result.Should().Pass(); | ||
| userSecretsId = result.StdOut!.Trim(); | ||
jjonescz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| new DotnetCommand(Log, "user-secrets", "set", "MySecret", "MyValue", "--id", userSecretsId) | ||
| .WithWorkingDirectory(testInstance.Path) | ||
| .Execute() | ||
| .Should().Pass(); | ||
| } | ||
| else | ||
| { | ||
| new DotnetCommand(Log, "user-secrets", "set", "MySecret", "MyValue", "--file", "Program.cs") | ||
| .WithWorkingDirectory(testInstance.Path) | ||
| .Execute() | ||
| .Should().Pass(); | ||
| } | ||
|
|
||
| Build(testInstance, BuildLevel.All, expectedOutput: """ | ||
| v1 | ||
| MySecret=MyValue (JsonConfigurationProvider for 'secrets.json' (Optional)) | ||
| """); | ||
|
|
||
| code = code.Replace("v1", "v2"); | ||
| File.WriteAllText(programPath, code); | ||
|
|
||
| Build(testInstance, BuildLevel.Csc, expectedOutput: """ | ||
| v2 | ||
| MySecret=MyValue (JsonConfigurationProvider for 'secrets.json' (Optional)) | ||
| """); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Verifies that msbuild-based runs use CSC args equivalent to csc-only runs. | ||
| /// Can regenerate CSC arguments template in <see cref="CSharpCompilerCommand"/>. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider making this just a parameter to
FindIncludedItems, in order to make things more clear. It feels unnecessary to rely on capture, when the variable is not used in the declaring method itself.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The most straightforward thing might be to delete the declaration here and restore the declaration in
FindIncludedItems().There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed with Rikki, that this is only referenced via capture is somewhat confusing. I'd personally just pass this as a parameter where needed.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, thanks, I extracted this line unintentionally (because it was in the block of code that I wanted to extract).
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the latest commit really addresses the concern, am I missing something? Or were Rikki and I commenting on different things? I assumed Rikki meant the entire
projectCollection/projectInstancedual locals; I'm not a fan of how they're only referenced via capture.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about pushing on the capture thing on more than just
entryPointFileDirectorybut decided I didn’t feel too strongly. However I would generally prefer that locals are not used as “capture only” even if multiple local functions are capturing them.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you saying we should never use non-static local functions?
I think some capturing makes for a cleaner code, although for code reviews I would recommend using VSCode with C# extension where you can actually hover over the function to see the captured variables.
I also don't like functions with a lot of "weakly" typed arguments (like
bools andstrings) as it's easy to pass the wrong thing to them. Capturing also helps with this, because you just reference the original thing by name.Given this is a pre-existing issue (the existing local functions are already capturing variables) and you both signed off, I'm going to merge this, but happy to discuss further and change things in a follow up PR if needed.