Skip to content
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

Change templates to be a single template. #792

Merged
merged 10 commits into from
Sep 15, 2017

Conversation

ILMTitan
Copy link

@ILMTitan ILMTitan commented Sep 5, 2017

Create a single template with a version and type selection dialog.
This is a fix for issues #781 and #782.

@ILMTitan ILMTitan self-assigned this Sep 5, 2017
@codecov
Copy link

codecov bot commented Sep 6, 2017

Codecov Report

Merging #792 into master will increase coverage by 1.1%.
The diff coverage is 88.38%.

Impacted file tree graph

@@            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
Impacted Files Coverage Δ
...xtension/GoogleCloudExtension/Utils/StringUtils.cs 100% <ø> (ø) ⬆️
...udExtension/Utils/LocalizedDisplayNameAttribute.cs 100% <ø> (ø) ⬆️
...ateChooserDialog/TemplateChooserWindowContent.xaml 0% <0%> (ø)
.../CloudExplorerSources/PubSub/TopicViewModelBase.cs 95.55% <0%> (-4.45%) ⬇️
...ChooserDialog/TemplateChooserWindowContent.xaml.cs 0% <0%> (ø)
...ogs/TemplateChooserDialog/TemplateChooserWindow.cs 0% <0%> (ø)
...leCloudExtension/Utils/EnumDisplayNameConverter.cs 0% <0%> (ø)
...lateWizards/GoogleProjectTemplateSelectorWizard.cs 100% <100%> (ø)
...ateChooserDialog/TemplateChooserViewModelResult.cs 100% <100%> (ø)
...ion/TemplateWizards/GoogleProjectTemplateWizard.cs 82.6% <100%> (-1.27%) ⬇️
... and 15 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8d925e1...1213b58. Read the comment docs.

@ivannaranjo
Copy link
Contributor

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?

Copy link
Contributor

@ivannaranjo ivannaranjo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
{

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty line.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

{
/// <summary>
/// Wizard for a project template. Delegates to GoogleProjecTemplateSelectorWizard
/// in GoogleCloudExtension.dll. That class can not be used directly because
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Author

@ILMTitan ILMTitan Sep 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comments.

/// 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is an empty string considered to be all digits? It should return false since by definition it does not contain digits.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also not my code.

/// </summary>
public static IEnumerable<string> SplitStringBySpaceOrQuote(string source)
{
if (source == null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the source is null or empty then you should probably return an empty enumerable no?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a function I wrote. This is a file being move into a different assembly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please open an issue so we can track fixing this code then.

{
get
{
if (_isMvc)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this should be an enum instead of booleans, since the type of template is mutually exclusive.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

<ResourceDictionary Source="../../../Theming/ThemingResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
<DataTemplate DataType="{x:Type local:FrameworkType}">
<TextBlock Text="{Binding Converter={utils:EnumDisplayNameConverter}}"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not unfinished. This method should never be called.


namespace GoogleCloudExtension.Utils
{
public class EnumDisplayNameConverter : MarkupExtension, IValueConverter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Jim Przybylinski added 2 commits September 13, 2017 14:27
Add Asp.Net Core 1.1 templates.
Add unit tests.
Enable ProjectTemplate.Tests with VS2017.
Copy link
Contributor

@ivannaranjo ivannaranjo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thank you! :)

@@ -71,11 +79,11 @@
<RadioButton
GroupName="AppType"
Content="{x:Static ext:Resources.WizardTemplateChooserMvcLabel}"
IsChecked="{Binding IsMvc}"/>
IsChecked="{Binding AppType, Converter={utils:RadioEnumConverter Target={x:Static local:AppType.Mvc}}}"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed this back to have IsMvc/IsWebApi properties on the ViewModel.

@@ -16,7 +16,15 @@
<ResourceDictionary Source="../../../Theming/ThemingResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
<DataTemplate DataType="{x:Type local:FrameworkType}">
<TextBlock Text="{Binding Converter={utils:EnumDisplayNameConverter}}"/>
<TextBlock x:Name="TextDisplay"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -16,7 +16,10 @@

<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" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Jim Przybylinski added 3 commits September 14, 2017 11:25
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.
Copy link
Contributor

@ivannaranjo ivannaranjo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really looking good, thank you for taking the feedback.

@ILMTitan ILMTitan merged commit 7e98c58 into GoogleCloudPlatform:master Sep 15, 2017
@ILMTitan ILMTitan deleted the single-template-dialog branch September 15, 2017 18:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants