Merge branch 'dev' into Issue196-FeedbackHub

This commit is contained in:
Raúl Alarcón 2017-10-03 07:30:54 +00:00 коммит произвёл GitHub
Родитель f4cdda05f2 24cbc6086e
Коммит 70d50a819d
22 изменённых файлов: 528 добавлений и 44 удалений

Просмотреть файл

@ -9,16 +9,26 @@ I need an app that uses MVVM Light, uses master detail, can suspend and resume,
## Build Status
|Branch |CI |Gen Tests |Full Tests |Test Version|Version|
|:--------|:----------------:|:---------------:|:---------------:|:---------------:|:---------------:|
|master|[![Build status](https://ci.appveyor.com/api/projects/status/nf8r35r45o4yqbqs/branch/master?svg=true)](https://ci.appveyor.com/project/ralarcon/windowstemplatestudio/branch/master)|[![Generation Tests](https://winappstudio.visualstudio.com/_apis/public/build/definitions/5c80cfe7-3bfb-4799-9d04-803c84df7a60/141/badge)](https://winappstudio.visualstudio.com/DefaultCollection/Vegas/_build/index?definitionId=141)|[![Full Integration Tests](https://winappstudio.visualstudio.com/_apis/public/build/definitions/5c80cfe7-3bfb-4799-9d04-803c84df7a60/129/badge)](https://winappstudio.visualstudio.com/DefaultCollection/Vegas/_build/index?definitionId=129)|[![Prerelease Version](https://wtsrepository.blob.core.windows.net/badges/img.prerelease.version.svg)](https://github.com/Microsoft/WindowsTemplateStudio/blob/master/docs/getting-started-extension.md#nightly--pre-release-feeds-for-windows-template-studio) |[![Production Version](https://wtsrepository.blob.core.windows.net/badges/img.release.version.svg)](https://marketplace.visualstudio.com/items?itemName=WASTeamAccount.WindowsTemplateStudio)|
|dev|[![Build status](https://ci.appveyor.com/api/projects/status/nf8r35r45o4yqbqs/branch/dev?svg=true)](https://ci.appveyor.com/project/ralarcon/windowstemplatestudio/branch/dev)|[![Generation Tests](https://winappstudio.visualstudio.com/_apis/public/build/definitions/5c80cfe7-3bfb-4799-9d04-803c84df7a60/135/badge)](https://winappstudio.visualstudio.com/DefaultCollection/Vegas/_build/index?definitionId=135)|[![Full Integration Tests](https://winappstudio.visualstudio.com/_apis/public/build/definitions/5c80cfe7-3bfb-4799-9d04-803c84df7a60/128/badge)](https://winappstudio.visualstudio.com/DefaultCollection/Vegas/_build/index?definitionId=128)|[![Nightly Version](https://wtsrepository.blob.core.windows.net/badges/img.nightly.version.svg)](https://github.com/Microsoft/WindowsTemplateStudio/blob/master/docs/getting-started-extension.md#nightly--pre-release-feeds-for-windows-template-studio)||
|Branch |CI |Test Version|Version|
|:--------|:----------------:|:---------------:|:---------------:|
|master|[![Build status](https://ci.appveyor.com/api/projects/status/nf8r35r45o4yqbqs/branch/master?svg=true)](https://ci.appveyor.com/project/ralarcon/windowstemplatestudio/branch/master)|[![Prerelease Version](https://wtsrepository.blob.core.windows.net/badges/img.prerelease.version.svg)](https://github.com/Microsoft/WindowsTemplateStudio/blob/master/docs/getting-started-extension.md#nightly--pre-release-feeds-for-windows-template-studio) |[![Production Version](https://wtsrepository.blob.core.windows.net/badges/img.release.version.svg)](https://marketplace.visualstudio.com/items?itemName=WASTeamAccount.WindowsTemplateStudio)|
|dev|[![Build status](https://ci.appveyor.com/api/projects/status/nf8r35r45o4yqbqs/branch/dev?svg=true)](https://ci.appveyor.com/project/ralarcon/windowstemplatestudio/branch/dev)|[![Nightly Version](https://wtsrepository.blob.core.windows.net/badges/img.nightly.version.svg)](https://github.com/Microsoft/WindowsTemplateStudio/blob/master/docs/getting-started-extension.md#nightly--pre-release-feeds-for-windows-template-studio)||
|Branch |Gen Tests |Full Tests |WACK Tests |
|:--------|:---------------:|:---------------:|:---------------:|
|master|[![Generation Tests](https://winappstudio.visualstudio.com/_apis/public/build/definitions/5c80cfe7-3bfb-4799-9d04-803c84df7a60/141/badge)](https://winappstudio.visualstudio.com/DefaultCollection/Vegas/_build/index?definitionId=141)|[![Full Integration Tests](https://winappstudio.visualstudio.com/_apis/public/build/definitions/5c80cfe7-3bfb-4799-9d04-803c84df7a60/129/badge)](https://winappstudio.visualstudio.com/DefaultCollection/Vegas/_build/index?definitionId=129)|
|dev|[![Generation Tests](https://winappstudio.visualstudio.com/_apis/public/build/definitions/5c80cfe7-3bfb-4799-9d04-803c84df7a60/135/badge)](https://winappstudio.visualstudio.com/DefaultCollection/Vegas/_build/index?definitionId=135)|[![Full Integration Tests](https://winappstudio.visualstudio.com/_apis/public/build/definitions/5c80cfe7-3bfb-4799-9d04-803c84df7a60/128/badge)](https://winappstudio.visualstudio.com/DefaultCollection/Vegas/_build/index?definitionId=128)|[![Wack Tests](https://winappstudio.visualstudio.com/DefaultCollection/_apis/public/build/definitions/5c80cfe7-3bfb-4799-9d04-803c84df7a60/142/badge)](https://winappstudio.visualstudio.com/DefaultCollection/Vegas/_build/index?definitionId=142)
> The builds include test verifications to validate the contributions:
> * *CI Build*: Includes all unit test + minimum integration verifications (minumum generation + build + code style rules). Runs every PR requested / PR accepted.
> * *Gen Tests*: Includes tests to verify combinations and variations of templates from a project generation point of view. Runs every PR accepted and takes a bit to complete.
> * *Full Tests*: Includes `Gen Tests` and actually builds the solutions generated to ensure no build time issues found. Runs every PR accepted and takes longer to be completed.
>
> * *Wack Tests*: Includes tests that run the App Certification Kit against the generated projects to ensure there are no issues blocking a submission to the store. Runs once nightly and takes quite a while to complete.
## Features

Просмотреть файл

@ -182,6 +182,8 @@
<Compile Include="Gen\GenToolBox.cs" />
<Compile Include="Gen\IContextProvider.cs" />
<Compile Include="PostActions\Catalog\FileNameSearchPostAction.cs" />
<Compile Include="PostActions\Catalog\Merge\MergeResourceDictionaryPostAction.cs" />
<Compile Include="PostActions\Catalog\Merge\ResourceDictionaryWriter.cs" />
<Compile Include="ProgrammingLanguages.cs" />
<Compile Include="Naming\SuggestedDirectoryNameValidator.cs" />
<Compile Include="PostActions\Catalog\Merge\FailedMergePostAction.cs" />

Просмотреть файл

@ -18,7 +18,7 @@ namespace Microsoft.Templates.Core.PostActions.Catalog.Merge
public override void Execute()
{
if (Regex.IsMatch(_config, MergePostAction.GlobalExtension))
if (Regex.IsMatch(_config, MergeConfiguration.GlobalExtension))
{
GetFileFromProject();
}
@ -55,16 +55,16 @@ namespace Microsoft.Templates.Core.PostActions.Catalog.Merge
private string GetMergeFileFromDirectory(string directory)
{
if (Path.GetFileName(_config).StartsWith(MergePostAction.Extension))
if (Path.GetFileName(_config).StartsWith(MergeConfiguration.Extension))
{
var extension = Path.GetExtension(_config);
return Directory.EnumerateFiles(directory, $"*{extension}").FirstOrDefault(f => !Regex.IsMatch(f, MergePostAction.PostactionRegex));
return Directory.EnumerateFiles(directory, $"*{extension}").FirstOrDefault(f => !Regex.IsMatch(f, MergeConfiguration.PostactionRegex));
}
else
{
var filePath = Path.Combine(directory, Path.GetFileName(_config));
var path = Regex.Replace(filePath, MergePostAction.PostactionRegex, ".");
var path = Regex.Replace(filePath, MergeConfiguration.PostactionRegex, ".");
return path;
}

Просмотреть файл

@ -12,6 +12,19 @@ namespace Microsoft.Templates.Core.PostActions.Catalog.Merge
{
public class MergeConfiguration
{
public const string Suffix = "postaction";
public const string NewSuffix = "failedpostaction";
public const string PostactionRegex = @"(\$\S*)?(_" + Suffix + "|_g" + Suffix + @")\.";
public const string FailedPostactionRegex = @"(\$\S*)?(_" + NewSuffix + "|_g" + NewSuffix + @")(\d)?\.";
public const string Extension = "_" + Suffix + ".";
public const string GlobalExtension = "$*_g" + Suffix + ".";
public const string ResourceDictionaryMatch = @"<ResourceDictionary
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">";
public string FilePath { get; private set; }
public bool FailOnError { get; private set; }

Просмотреть файл

@ -7,6 +7,7 @@ namespace Microsoft.Templates.Core.PostActions.Catalog.Merge
public enum MergeFailureType
{
FileNotFound,
LineNotFound
LineNotFound,
KeyAlreadyDefined
}
}

Просмотреть файл

@ -16,15 +16,6 @@ namespace Microsoft.Templates.Core.PostActions.Catalog.Merge
{
public class MergePostAction : PostAction<MergeConfiguration>
{
private const string Suffix = "postaction";
private const string NewSuffix = "failedpostaction";
public const string Extension = "_" + Suffix + ".";
public const string GlobalExtension = "$*_g" + Suffix + ".";
public const string PostactionRegex = @"(\$\S*)?(_" + Suffix + "|_g" + Suffix + @")\.";
public const string FailedPostactionRegex = @"(\$\S*)?(_" + NewSuffix + "|_g" + NewSuffix + @")(\d)?\.";
public MergePostAction(MergeConfiguration config) : base(config)
{
}
@ -80,32 +71,36 @@ namespace Microsoft.Templates.Core.PostActions.Catalog.Merge
File.Delete(_config.FilePath);
}
private void AddFailedMergePostActionsFileNotFound(string originalFilePath)
protected void AddFailedMergePostActions(string originalFilePath, MergeFailureType mergeFailureType, string description)
{
var sourceFileName = originalFilePath.Replace(GenContext.Current.OutputPath + Path.DirectorySeparatorChar, string.Empty);
var postactionFileName = _config.FilePath.Replace(GenContext.Current.OutputPath + Path.DirectorySeparatorChar, string.Empty);
var description = string.Format(StringRes.FailedMergePostActionFileNotFound, sourceFileName);
var sourceFileName = GetRelativePath(originalFilePath);
var postactionFileName = GetRelativePath(_config.FilePath);
var failedFileName = GetFailedPostActionFileName();
GenContext.Current.FailedMergePostActions.Add(new FailedMergePostAction(sourceFileName, _config.FilePath, failedFileName, description, MergeFailureType.FileNotFound));
GenContext.Current.FailedMergePostActions.Add(new FailedMergePostAction(sourceFileName, _config.FilePath, failedFileName, description, mergeFailureType));
File.Copy(_config.FilePath, failedFileName, true);
}
protected string GetRelativePath(string path)
{
return path.Replace(GenContext.Current.OutputPath + Path.DirectorySeparatorChar, string.Empty);
}
private void AddFailedMergePostActionsFileNotFound(string originalFilePath)
{
var description = string.Format(StringRes.FailedMergePostActionFileNotFound, GetRelativePath(originalFilePath));
AddFailedMergePostActions(originalFilePath, MergeFailureType.FileNotFound, description);
}
private void AddFailedMergePostActionsAddLineNotFound(string originalFilePath, string errorLine)
{
var sourceFileName = originalFilePath.Replace(GenContext.Current.OutputPath + Path.DirectorySeparatorChar, string.Empty);
var postactionFileName = _config.FilePath.Replace(GenContext.Current.OutputPath + Path.DirectorySeparatorChar, string.Empty);
var description = string.Format(StringRes.FailedMergePostActionLineNotFound, errorLine.Trim(), sourceFileName);
var failedFileName = GetFailedPostActionFileName();
GenContext.Current.FailedMergePostActions.Add(new FailedMergePostAction(sourceFileName, _config.FilePath, failedFileName, description, MergeFailureType.LineNotFound));
File.Copy(_config.FilePath, failedFileName, true);
var description = string.Format(StringRes.FailedMergePostActionLineNotFound, errorLine.Trim(), GetRelativePath(originalFilePath));
AddFailedMergePostActions(originalFilePath, MergeFailureType.LineNotFound, description);
}
private string GetFailedPostActionFileName()
{
var newFileName = Path.GetFileNameWithoutExtension(_config.FilePath).Replace(Suffix, NewSuffix);
var newFileName = Path.GetFileNameWithoutExtension(_config.FilePath).Replace(MergeConfiguration.Suffix, MergeConfiguration.NewSuffix);
var folder = Path.GetDirectoryName(_config.FilePath);
var extension = Path.GetExtension(_config.FilePath);
@ -120,16 +115,16 @@ namespace Microsoft.Templates.Core.PostActions.Catalog.Merge
private string GetFilePath()
{
if (Path.GetFileName(_config.FilePath).StartsWith(Extension, StringComparison.InvariantCultureIgnoreCase))
if (Path.GetFileName(_config.FilePath).StartsWith(MergeConfiguration.Extension, StringComparison.InvariantCultureIgnoreCase))
{
var extension = Path.GetExtension(_config.FilePath);
var directory = Path.GetDirectoryName(_config.FilePath);
return Directory.EnumerateFiles(directory, $"*{extension}").FirstOrDefault(f => !f.Contains(Suffix));
return Directory.EnumerateFiles(directory, $"*{extension}").FirstOrDefault(f => !f.Contains(MergeConfiguration.Suffix));
}
else
{
var path = Regex.Replace(_config.FilePath, PostactionRegex, ".");
var path = Regex.Replace(_config.FilePath, MergeConfiguration.PostactionRegex, ".");
return path;
}

Просмотреть файл

@ -0,0 +1,117 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Templates.Core.Gen;
using Microsoft.Templates.Core.Resources;
namespace Microsoft.Templates.Core.PostActions.Catalog.Merge
{
public class MergeResourceDictionaryPostAction : MergePostAction
{
private const string mergeDictionaryPattern = @"<ResourceDictionary.MergedDictionaries>
<!--^^-->
<!--{[{-->
<ResourceDictionary Source=""{filePath}""/>
<!--}]}-->
</ResourceDictionary.MergedDictionaries>";
public MergeResourceDictionaryPostAction(MergeConfiguration config) : base(config)
{
}
public override void Execute()
{
string originalFilePath = GetFilePath();
if (!File.Exists(originalFilePath))
{
File.Copy(_config.FilePath, originalFilePath);
GenContext.Current.ProjectItems.Add(originalFilePath);
AddToMergeDictionary(originalFilePath);
}
else
{
var mergeRoot = XElement.Load(_config.FilePath);
var sourceRoot = XElement.Load(originalFilePath);
foreach (var node in GetNodesToMerge(mergeRoot))
{
var sourceNode = sourceRoot.Elements().FirstOrDefault(e => GetKey(e) == GetKey(node));
if (sourceNode == null)
{
AddNodeToSource(sourceRoot, node);
}
else
{
if (!XNode.DeepEquals(node, sourceNode))
{
var errorMessage = string.Format(StringRes.FailedMergePostActionKeyAlreadyDefined, GetKey(node), GetRelativePath(originalFilePath));
if (_config.FailOnError)
{
throw new InvalidDataException(errorMessage);
}
else
{
AddFailedMergePostActions(originalFilePath, MergeFailureType.KeyAlreadyDefined, errorMessage);
File.Delete(_config.FilePath);
return;
}
}
}
}
using (TextWriter writeFile = new StreamWriter(originalFilePath))
{
var writer = new ResourceDictionaryWriter(writeFile);
writer.WriteResourceDictionary(sourceRoot);
writer.Flush();
writer.Close();
}
}
File.Delete(_config.FilePath);
}
private static void AddToMergeDictionary(string originalFilePath)
{
var relPath = originalFilePath.Replace(GenContext.Current.OutputPath, "").Replace(@"\", @"/");
var postactionContent = mergeDictionaryPattern.Replace("{filePath}", relPath);
var mergeDictionaryName = Path.GetFileNameWithoutExtension(originalFilePath);
File.WriteAllText(GenContext.Current.OutputPath + $"/App${mergeDictionaryName}_gpostaction.xaml", postactionContent);
}
private static void AddNodeToSource(XElement sourceRoot, XElement node)
{
if (node.PreviousNode != null && node.PreviousNode.NodeType == XmlNodeType.Comment)
{
sourceRoot.Add(node.PreviousNode);
}
sourceRoot.Add(node);
}
private string GetKey(XElement node)
{
XNamespace ns = node.GetNamespaceOfPrefix("x");
return node.Attribute(ns + "Key").Value;
}
private IEnumerable<XElement> GetNodesToMerge(XElement rootNode)
{
return rootNode.Descendants().Where(e => e.Attributes().Any(a => a.Name.LocalName == "Key"));
}
private string GetFilePath()
{
return Regex.Replace(_config.FilePath, MergeConfiguration.PostactionRegex, ".");
}
}
}

Просмотреть файл

@ -0,0 +1,133 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace Microsoft.Templates.Core.PostActions.Catalog.Merge
{
public class ResourceDictionaryWriter : XmlTextWriter
{
private TextWriter writer;
private const string intend = " ";
public ResourceDictionaryWriter(TextWriter w) : base(w)
{
writer = w;
}
public ResourceDictionaryWriter(Stream w, Encoding encoding) : base(w, encoding)
{
}
public ResourceDictionaryWriter(string filename, Encoding encoding) : base(filename, encoding)
{
}
public override void WriteStartElement(string prefix, string localName, string ns)
{
if (!string.IsNullOrEmpty(prefix))
{
localName = prefix + ":" + localName;
prefix = "";
}
base.WriteStartElement(prefix, localName, ns);
}
public new void WriteAttributeString(string prefix, string localName, string value)
{
if (!string.IsNullOrEmpty(prefix))
{
localName = prefix + ":" + localName;
}
WriteAttributeString(localName, value);
}
public void WriteResourceDictionary(XElement e)
{
WriteStartElement(e.Name.LocalName);
WriteNamespaceDeclaration("xmlns", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
WriteNamespaceDeclaration("xmlns:x", "http://schemas.microsoft.com/winfx/2006/xaml");
WriteNewLine();
WriteNewLine();
foreach (var node in e.Elements())
{
WriteElement(node);
}
WriteFullEndElement();
WriteNewLine();
}
private void WriteElement(XElement e)
{
WriteComments(e);
WriteRaw(intend);
WriteStartElement(e.GetPrefixOfNamespace(e.Name.Namespace), e.Name.LocalName, "");
WriteAttributes(e);
if (e.Descendants().Count() > 0)
{
WriteChildElements(e);
}
else
{
WriteRaw(e.Value);
}
WriteEndElement();
WriteNewLine();
if (e.Name.LocalName == "Style")
{
WriteNewLine();
}
}
private void WriteNewLine()
{
WriteRaw("\r\n");
}
private void WriteNamespaceDeclaration(string key, string value)
{
writer.WriteLine();
WriteAttributeString(" " + key, value);
}
private void WriteComments(XElement e)
{
if (e.PreviousNode != null && e.PreviousNode.NodeType == XmlNodeType.Comment)
{
WriteRaw(intend);
WriteComment((e.PreviousNode as XComment).Value);
WriteNewLine();
}
}
private void WriteChildElements(XElement e)
{
WriteNewLine();
foreach (var n in e.Descendants())
{
WriteRaw(intend);
WriteRaw(intend);
WriteStartElement(e.GetPrefixOfNamespace(n.Name.Namespace), n.Name.LocalName, "");
WriteAttributes(n);
WriteEndElement();
WriteNewLine();
}
WriteRaw(intend);
}
private void WriteAttributes(XElement e)
{
foreach (var a in e.Attributes())
{
WriteAttributeString(e.GetPrefixOfNamespace(a.Name.Namespace), a.Name.LocalName, a.Value);
}
}
}
}

Просмотреть файл

@ -21,7 +21,7 @@ namespace Microsoft.Templates.Core.PostActions
AddFileNameSearchActions(genInfo, postActions);
AddGetMergeFilesFromProjectPostAction(postActions);
AddGenerateMergeInfoPostAction(postActions);
AddMergeActions(postActions, $"*{MergePostAction.Extension}*", false);
AddMergeActions(postActions, $"*{MergeConfiguration.Extension}*", false);
return postActions;
}
@ -30,7 +30,7 @@ namespace Microsoft.Templates.Core.PostActions
{
var postActions = new List<PostAction>();
AddGlobalMergeActions(postActions, $"*{MergePostAction.GlobalExtension}*", false);
AddGlobalMergeActions(postActions, $"*{MergeConfiguration.GlobalExtension}*", false);
postActions.Add(new SortUsingsPostAction());
postActions.Add(new SortImportsPostAction());

Просмотреть файл

@ -20,7 +20,7 @@ namespace Microsoft.Templates.Core.PostActions
AddFileNameSearchActions(genInfo, postActions);
AddPredefinedActions(genInfo, genResult, postActions);
AddMergeActions(postActions, $"*{MergePostAction.Extension}*", true);
AddMergeActions(postActions, $"*{MergeConfiguration.Extension}*", true);
AddSearchAndReplaceActions(postActions, $"*{SearchAndReplacePostAction.Extension}*");
return postActions;
@ -30,7 +30,7 @@ namespace Microsoft.Templates.Core.PostActions
{
var postActions = new List<PostAction>();
AddGlobalMergeActions(postActions, $"*{MergePostAction.GlobalExtension}*", true);
AddGlobalMergeActions(postActions, $"*{MergeConfiguration.GlobalExtension}*", true);
postActions.Add(new SortUsingsPostAction());
postActions.Add(new SortImportsPostAction());
postActions.Add(new AddContextItemsToProjectPostAction());

Просмотреть файл

@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -34,7 +35,7 @@ namespace Microsoft.Templates.Core.PostActions
{
Directory
.EnumerateFiles(GenContext.Current.OutputPath, "*.*", SearchOption.AllDirectories)
.Where(f => Regex.IsMatch(f, MergePostAction.PostactionRegex))
.Where(f => Regex.IsMatch(f, MergeConfiguration.PostactionRegex))
.ToList()
.ForEach(f => postActions.Add(new GetMergeFilesFromProjectPostAction(f)));
}
@ -43,7 +44,7 @@ namespace Microsoft.Templates.Core.PostActions
{
Directory
.EnumerateFiles(GenContext.Current.OutputPath, "*.*", SearchOption.AllDirectories)
.Where(f => Regex.IsMatch(f, MergePostAction.PostactionRegex))
.Where(f => Regex.IsMatch(f, MergeConfiguration.PostactionRegex))
.ToList()
.ForEach(f => postActions.Add(new GenerateMergeInfoPostAction(f)));
}
@ -71,7 +72,7 @@ namespace Microsoft.Templates.Core.PostActions
Directory
.EnumerateFiles(GenContext.Current.OutputPath, searchPattern, SearchOption.AllDirectories)
.ToList()
.ForEach(f => postActions.Add(new MergePostAction(new MergeConfiguration(f, failOnError))));
.ForEach(f => AddMergePostAction(postActions, failOnError, f));
}
internal void AddFileNameSearchActions(GenInfo genInfo, List<PostAction> postActions)
@ -100,5 +101,22 @@ namespace Microsoft.Templates.Core.PostActions
.ToList()
.ForEach(f => postActions.Add(new SearchAndReplacePostAction(f)));
}
private static void AddMergePostAction(List<PostAction> postActions, bool failOnError, string f)
{
if (IsResourceDictionaryPostaction(f))
{
postActions.Add(new MergeResourceDictionaryPostAction(new MergeConfiguration(f, failOnError)));
}
else
{
postActions.Add(new MergePostAction(new MergeConfiguration(f, failOnError)));
}
}
private static bool IsResourceDictionaryPostaction(string f)
{
return Path.GetExtension(f).ToLower() == ".xaml" & File.ReadAllText(f).StartsWith(MergeConfiguration.ResourceDictionaryMatch);
}
}
}

9
code/src/Core/Resources/StringRes.Designer.cs сгенерированный
Просмотреть файл

@ -150,6 +150,15 @@ namespace Microsoft.Templates.Core.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Key {0} already defined with different value or elements in file &apos;{1}&apos;.
/// </summary>
internal static string FailedMergePostActionKeyAlreadyDefined {
get {
return ResourceManager.GetString("FailedMergePostActionKeyAlreadyDefined", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Could not find the expected line `{0}` in file &apos;{1}&apos;. Please merge the content from the postaction file manually..
/// </summary>

Просмотреть файл

@ -384,4 +384,7 @@ The following changes could not be integrated: {2}
<data name="TemplatesSynchronizationWarnReadingLockFileMessage" xml:space="preserve">
<value>Error reading the instance locking file.</value>
</data>
<data name="FailedMergePostActionKeyAlreadyDefined" xml:space="preserve">
<value>Key {0} already defined with different value or elements in file '{1}'</value>
</data>
</root>

Просмотреть файл

@ -132,7 +132,7 @@ namespace Microsoft.Templates.UI
var result = new TempGenerationResult();
var files = Directory
.EnumerateFiles(GenContext.Current.OutputPath, "*", SearchOption.AllDirectories)
.Where(f => !Regex.IsMatch(f, MergePostAction.PostactionRegex) && !Regex.IsMatch(f, MergePostAction.FailedPostactionRegex))
.Where(f => !Regex.IsMatch(f, MergeConfiguration.PostactionRegex) && !Regex.IsMatch(f, MergeConfiguration.FailedPostactionRegex))
.ToList();
foreach (var file in files)

Просмотреть файл

@ -146,6 +146,7 @@
<Compile Include="Diagnostics\TestHealthWriter.cs" />
<Compile Include="Localization\LocalizationTest.cs" />
<Compile Include="PostActions\Catalog\HandleRemovalsTest.cs" />
<Compile Include="PostActions\Catalog\MergeResourceDictionaryPostactionTest.cs" />
<Compile Include="PostActions\Catalog\SortImportsTest.cs" />
<Compile Include="PostActions\Catalog\SortUsingsTest.cs" />
<Compile Include="Templates\ITemplateInfoExtensionsTest.cs" />
@ -272,6 +273,40 @@
<Analyzer Include="..\..\packages\StyleCop.Analyzers.1.0.2\analyzers\dotnet\cs\StyleCop.Analyzers.CodeFixes.dll" />
<Analyzer Include="..\..\packages\StyleCop.Analyzers.1.0.2\analyzers\dotnet\cs\StyleCop.Analyzers.dll" />
</ItemGroup>
<ItemGroup>
<None Include="TestData\Merge\Style.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="TestData\Merge\Style_postaction.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
<SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="TestData\Merge\Style_expected.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
<SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="TestData\Merge\Style_fail_postaction.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
<SubType>Designer</SubType>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="TestData\Merge\Style_fail.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<SubType>Designer</SubType>
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>IF EXIST "$(ProjectDir)test.config.json.with.secrets" COPY /Y "$(ProjectDir)test.config.json.with.secrets" "$(TargetDir)test.config.json"</PostBuildEvent>

Просмотреть файл

@ -0,0 +1,71 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Templates.Core.Diagnostics;
using Microsoft.Templates.Core.Gen;
using Microsoft.Templates.Core.PostActions.Catalog.Merge;
using Xunit;
namespace Microsoft.Templates.Core.Test.PostActions.Catalog
{
[Trait("ExecutionSet", "Minimum")]
public class MergeResourceDictionaryPostactionTest : IContextProvider
{
public string ProjectName => throw new NotImplementedException();
public string OutputPath => Directory.GetCurrentDirectory();
public string ProjectPath => throw new NotImplementedException();
public List<string> ProjectItems => throw new NotImplementedException();
public List<string> FilesToOpen => throw new NotImplementedException();
public List<FailedMergePostAction> FailedMergePostActions => throw new NotImplementedException();
public Dictionary<string, List<MergeInfo>> MergeFilesFromProject => throw new NotImplementedException();
public Dictionary<ProjectMetricsEnum, double> ProjectMetrics => throw new NotImplementedException();
[Fact]
public void MergeResourceDictionaryPostaction()
{
var source = Path.GetFullPath(@".\TestData\Merge\Style.xaml");
var postaction = Path.GetFullPath(@".\TestData\Merge\Style_postaction.xaml");
var expected = File.ReadAllText(@".\TestData\Merge\Style_expected.xaml").Replace("\r\n", "");
var config = new MergeConfiguration(postaction, true);
var mergeResourceDictionaryPostAction = new MergeResourceDictionaryPostAction(config);
mergeResourceDictionaryPostAction.Execute();
var result = File.ReadAllText(source).Replace("\r\n", "");
Assert.Equal(result, expected);
}
[Fact]
public void MergeResourceDictionaryPostaction_Failing()
{
var source = Path.GetFullPath(@".\TestData\Merge\Style_fail.xaml");
var postaction = Path.GetFullPath(@".\TestData\Merge\Style_fail_postaction.xaml");
var expected = File.ReadAllText(@".\TestData\Merge\Style_expected.xaml");
GenContext.Current = this;
var config = new MergeConfiguration(postaction, true);
var mergeResourceDictionaryPostAction = new MergeResourceDictionaryPostAction(config);
Exception ex = Assert.Throws<InvalidDataException>(() => mergeResourceDictionaryPostAction.Execute());
Assert.Equal($"Key PageTitleStyle already defined with different value or elements in file '{source.Replace(GenContext.Current.OutputPath + Path.DirectorySeparatorChar, "")}'", ex.Message);
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Double x:Key="LargeFontSize">28</x:Double>
<x:Double x:Key="MediumFontSize">16</x:Double>
</ResourceDictionary>

Просмотреть файл

@ -0,0 +1,19 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Double x:Key="LargeFontSize">28</x:Double>
<x:Double x:Key="MediumFontSize">16</x:Double>
<x:Double x:Key="NewFontSize">5</x:Double>
<!--Common texts-->
<Style x:Key="PageTitleStyle" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="SemiLight" />
<Setter Property="FontSize" Value="{StaticResource LargeFontSize}" />
<Setter Property="TextTrimming" Value="CharacterEllipsis" />
<Setter Property="TextWrapping" Value="NoWrap" />
<Setter Property="Margin" Value="{StaticResource PageTitleMargin}" />
</Style>
</ResourceDictionary>

Просмотреть файл

@ -0,0 +1,15 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Double x:Key="LargeFontSize">28</x:Double>
<x:Double x:Key="MediumFontSize">16</x:Double>
<Style x:Key="PageTitleStyle" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="FontWeight" Value="SemiLight"/>
<Setter Property="FontSize" Value="{StaticResource LargeFontSize}"/>
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
<Setter Property="TextWrapping" Value="NoWrap"/>
<Setter Property="Margin" Value="{StaticResource PageTitleMargin}"/>
</Style>
</ResourceDictionary>

Просмотреть файл

@ -0,0 +1,16 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Double x:Key="MediumFontSize">16</x:Double>
<Style x:Key="PageTitleStyle" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="FontWeight" Value="SemiLight123"/>
<Setter Property="FontSize" Value="{StaticResource LargeFontSize}"/>
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
<Setter Property="TextWrapping" Value="NoWrap"/>
<Setter Property="Margin" Value="{StaticResource PageTitleMargin}"/>
</Style>
<x:Double x:Key="NewFontSize">5</x:Double>
</ResourceDictionary>

Просмотреть файл

@ -0,0 +1,16 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Double x:Key="MediumFontSize">16</x:Double>
<x:Double x:Key="NewFontSize">5</x:Double>
<!--Common texts-->
<Style x:Key="PageTitleStyle" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="FontWeight" Value="SemiLight"/>
<Setter Property="FontSize" Value="{StaticResource LargeFontSize}"/>
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
<Setter Property="TextWrapping" Value="NoWrap"/>
<Setter Property="Margin" Value="{StaticResource PageTitleMargin}"/>
</Style>
</ResourceDictionary>

Просмотреть файл

@ -99,6 +99,10 @@ The following list shows which tests are executed in which build. Within the Tem
* ExecutionSet=BuildStyleCop
* ExecutionSet=TemplateValidation
* VSO 'Templates.Test.Wack' Build (Wack Tests):
* Templates.Test
* ExecutionSet=ManualOnly
To shorten test execution time traits in Templates.Test are run parallel using this [script](../_build/ParallelTestExecution.ps1).
To execute this script locally use the following powershell command: