Merge branch 'dev' into Issue196-FeedbackHub
This commit is contained in:
Коммит
70d50a819d
20
README.md
20
README.md
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 '{1}'.
|
||||
/// </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 '{1}'. 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:
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче