Change templates to be a single template. - #792
Conversation
Codecov Report
@@ Coverage Diff @@
## master #792 +/- ##
=========================================
+ Coverage 10.46% 11.57% +1.1%
=========================================
Files 496 504 +8
Lines 12130 12299 +169
=========================================
+ Hits 1270 1423 +153
- Misses 10860 10876 +16
Continue to review full report at Codecov.
|
|
I'll go through the massive changelist to perform some spot checks, any guidance on what to expect would be great. Also, is the feature complete? Should this be in its own branch until the templates are fully functional? |
ivannaranjo
left a comment
There was a problem hiding this comment.
I am now convinced that this change should not go against the master branch. The feature is not complete and therefore it should go against a private branch were we can iterate freely. Please change the target of the PR.
I did not look at the templates themselves, there are waaay too many files to do an effective review there. We'll have to go one by one, generating the various combinations and looking at the generated code.
|
|
||
| namespace GoogleCloudExtension.TemplateWizards | ||
| { | ||
|
|
| { | ||
| /// <summary> | ||
| /// Wizard for a project template. Delegates to GoogleProjecTemplateSelectorWizard | ||
| /// in GoogleCloudExtension.dll. That class can not be used directly because |
There was a problem hiding this comment.
Could you ellaborate a bit about the issues? Open an issue in the github repo so we can track this issue and point to it.
There was a problem hiding this comment.
When I first tried to reference a wizard class in GoogleCloudExtension.dll from a vstemplate file, I got an error popup about being unable to reference a class from an MEF assembly (which GoogleCloudExtension.dll, containing the package, is).
There was a problem hiding this comment.
Please on an issue so we can come back to this again later and fix it, if you think that this can be eventually fixed.
| { | ||
| var fromUri = new Uri(fromDirectory.EnsureEndSeparator().Replace('\\', '/')); | ||
| var toUri = new Uri(toDirectory.EnsureEndSeparator().Replace('\\', '/')); | ||
| return fromUri.MakeRelativeUri(toUri).ToString().Replace('/', Path.DirectorySeparatorChar); |
There was a problem hiding this comment.
You are only using Path.DirectorySeparatorChar here, but not above, you should use it everywhere in this method to be consistent.
The documentation is not exactly clear on what the relative path from one directory to another means, I would suggest adding an example.
There was a problem hiding this comment.
I don't use it above, because I want to convert both types of directory separators to '/' so Uri will treat them as expected. I use it here because I am converting back to the native format.
There was a problem hiding this comment.
Hmm... Perhaps a comment on what you are doing would make this code clearer to read. Also, our code for VS is mostly Windows specific (i.e. not portable) so we can always assume that \ will be the path separator.
| /// return false if it is null. | ||
| /// Empty string is valid so it returns true. | ||
| /// </summary> | ||
| public static bool IsDigitsOnly(string text) => text != null && text.All(char.IsDigit); |
There was a problem hiding this comment.
Why is an empty string considered to be all digits? It should return false since by definition it does not contain digits.
| /// </summary> | ||
| public static IEnumerable<string> SplitStringBySpaceOrQuote(string source) | ||
| { | ||
| if (source == null) |
There was a problem hiding this comment.
If the source is null or empty then you should probably return an empty enumerable no?
There was a problem hiding this comment.
This is not a function I wrote. This is a file being move into a different assembly.
There was a problem hiding this comment.
Please open an issue so we can track fixing this code then.
| { | ||
| get | ||
| { | ||
| if (_isMvc) |
There was a problem hiding this comment.
Seems like this should be an enum instead of booleans, since the type of template is mutually exclusive.
| <ResourceDictionary Source="../../../Theming/ThemingResources.xaml"/> | ||
| </ResourceDictionary.MergedDictionaries> | ||
| <DataTemplate DataType="{x:Type local:FrameworkType}"> | ||
| <TextBlock Text="{Binding Converter={utils:EnumDisplayNameConverter}}"/> |
There was a problem hiding this comment.
Too much magic, just have this in the view model, which is the class responsible for talking to the view. The enums should always be view agnostic, including not having the localized string attached to them.
|
|
||
| string version = result.SelectedVersion.Version; | ||
| string templatePath = Path.Combine( | ||
| thisTemplateDirectory, "..", "..", "..", result.AppType, "1033", version, $"{version}.vstemplate"); |
There was a problem hiding this comment.
I applaud the effort, but the code is Windows specific. You can specify a format string that will create the right path without using this. Is ok to hard code the '' for file paths on Windows specific code.
There was a problem hiding this comment.
Changes this to use Path.DirectoryName multiple times.
| /// <inheritdoc/> | ||
| public void RunFinished() | ||
| { | ||
| throw new NotImplementedException("This wizard should delegate to another wizard and cancel itself."); |
There was a problem hiding this comment.
This tells me that this PR should go against a separate feature branch, not the master branch, as we should not be committing unfinished features there.
There was a problem hiding this comment.
This is not unfinished. This method should never be called.
|
|
||
| namespace GoogleCloudExtension.Utils | ||
| { | ||
| public class EnumDisplayNameConverter : MarkupExtension, IValueConverter |
There was a problem hiding this comment.
Please don't use this, enums should not have a localized display string associated with them.
| /// <summary> | ||
| /// The selected framework type. | ||
| /// </summary> | ||
| public FrameworkType SelectedFramework { get; } |
There was a problem hiding this comment.
I'm now even more convinced that we should not have localized strings associated with the enums like this. We should have a small class that associates the enum with the localized string, including one with the default value if necessary.
| public class TemplateChooserViewModel : ViewModelBase | ||
| { | ||
| private string _gcpProjectId; | ||
| private FrameworkType _selectedFramework = (FrameworkType)(-1); |
There was a problem hiding this comment.
You should instead define an enum value of None (which should be set to 0 btw) to indicate that there's no framework selected. This is one of the reasons why having magic to associate strings with enums does not work.
Add Asp.Net Core 1.1 templates. Add unit tests. Enable ProjectTemplate.Tests with VS2017.
ivannaranjo
left a comment
There was a problem hiding this comment.
Comments about over complicated XAML constructs.
Also, make sure that the .csproj are idiomatic. For the 2.0 case Microsoft made a big case of making it very very simple, we should follow suit and have the same idiomatic projects.
| /// </summary> | ||
| public enum AppType | ||
| { | ||
| None, |
There was a problem hiding this comment.
Nit, have a small comment for each option, helps when using it in intellisense. They are self-explanatory I know, but it will help in the long run.
|
|
||
| private string _gcpProjectId; | ||
| private FrameworkType _selectedFramework = (FrameworkType)(-1); | ||
| private FrameworkType _selectedFramework = FrameworkType.None; |
| GroupName="AppType" | ||
| Content="{x:Static ext:Resources.WizardTemplateChooserMvcLabel}" | ||
| IsChecked="{Binding IsMvc}"/> | ||
| IsChecked="{Binding AppType, Converter={utils:RadioEnumConverter Target={x:Static local:AppType.Mvc}}}"/> |
There was a problem hiding this comment.
I have to ask, what is the advantage of this vs. what you had before? Since the set of choices is well known, and limited, why having the extra complexity that your solution adds? If we were to have 10s of choices I would agree, but we only have 2 choices, and I don't think that we will ever have more than 4. Having it hardcoded in the UI is perfectly valid.
There was a problem hiding this comment.
Changed this back to have IsMvc/IsWebApi properties on the ViewModel.
| </ResourceDictionary.MergedDictionaries> | ||
| <DataTemplate DataType="{x:Type local:FrameworkType}"> | ||
| <TextBlock Text="{Binding Converter={utils:EnumDisplayNameConverter}}"/> | ||
| <TextBlock x:Name="TextDisplay"/> |
There was a problem hiding this comment.
Wouldn't it be simpler to just have two entries under the ComboBox with the two options? I'm sorry but this solution is waaay more complex than what it really needs to be. You can even use the Tag property in the TextBlock to contain the value of the enum that you want and just add two TextBlock instances.
| <ItemGroup> | ||
| <PackageReference Include="Google.Cloud.Diagnostics.AspNetCore" Version="1.0.0" /> | ||
| <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> | ||
| <PackageReference Include="Microsoft.AspNetCore" Version="2.0.0" /> |
There was a problem hiding this comment.
Looking at a 2.0 project generated by dotnet, it is much much simpler, it collapses all of these packages into:
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
</ItemGroup>We should make sure that the generated .csproj files are idiomatic.
Change framework type enum combobox to use ComboBoxItems. Change ASP.NET Core 2.0 templates to use Microsoft.AspNetCore.All.
Move EnsureEndSeparator to PathUtils. Add unit tests.
ivannaranjo
left a comment
There was a problem hiding this comment.
Really looking good, thank you for taking the feedback.
Create a single template with a version and type selection dialog.
This is a fix for issues #781 and #782.