From b3852c0b7804b202c4966e91824bb42ccbfe1445 Mon Sep 17 00:00:00 2001 From: Dirk Rombauts Date: Wed, 29 Jun 2016 16:10:48 +0200 Subject: [PATCH] Release 2.8.0 (#355) * Enhancement to support Unix path! (#344) I'm not sure you already got a try or a feedback about it but actually pickles run relatively well under Linux with mono which is interesting when like me you can't get a windows machine. However without this little change we can't get the folder structure display correctly. Could you integrate this modification? Thanks * Release 2.6.3 (#348) * Version Bump * Update change log * Add --enableComments Flag to Command Line - Default to True (#346) * Command-Line Flag --comments - Default to True - Incl Unit Test * Changed Command Line Argument --comments to --enableComments * Added Enable Comments Option to MSBuild - Powershell - WPF Runners * Fixed Bug with enableComments Property Not Being Used in MainViewModel * Release 2.7.0 (#352) * Release 2.6.3 (#347) * Enhancement to support Unix path! (#344) I'm not sure you already got a try or a feedback about it but actually pickles run relatively well under Linux with mono which is interesting when like me you can't get a windows machine. However without this little change we can't get the folder structure display correctly. Could you integrate this modification? Thanks * Version Bump * Update change log * Add EnableComments to the targets file * Adapt change log * Version bump to 2.7.0 * #320 - Scenario Deep Linking - DHTML and HTML Output (#350) * #320 - Scenario Deep Linking - DHTML and HTML Output * #320 - Fix Failing Unit Tests * #320 - Resolved Issue with Image Resource Not Copying * #320 - Add Backward-Compatibility for Hashed Feature Path * #320 - Added Modal Dialog for Link Copy * Edit release notes * Version Bump (2.8.0) --- CHANGELOG.md | 6 + build.bat | 2 +- src/Pickles/Pickles.BaseDhtmlFiles/Index.html | 98 ++++++++++-- .../Pickles.BaseDhtmlFiles/css/styles.css | 34 +++- .../Pickles.BaseDhtmlFiles/img/link.png | Bin 0 -> 413 bytes .../js/featureSearch.js | 71 ++++++++- .../js/featuresModel.js | 4 +- .../ObjectModel/IFeatureElement.cs | 2 + .../ObjectModel/Scenario.cs | 23 +-- .../ObjectModel/ScenarioBase.cs | 53 +++++++ .../ObjectModel/ScenarioOutline.cs | 25 +-- .../Pickles.ObjectModel.csproj | 1 + .../JSON/FormattingAFeature.feature | 2 + .../JSON/FormattingAFeature.feature.cs | 150 +++++++++--------- .../Json/FeatureToJsonFeatureMapperTests.cs | 1 + ...OutlineToJsonScenarioOutlineMapperTests.cs | 12 ++ .../Json/ScenarioToJsonScenarioMapperTests.cs | 12 ++ .../ObjectModel/MapperTestsForScenario.cs | 18 +++ .../MapperTestsForScenarioOutline.cs | 17 ++ .../DHTML/DhtmlResourceWriter.cs | 5 +- .../HTML/HtmlScenarioFormatter.cs | 22 ++- .../HTML/HtmlScenarioOutlineFormatter.cs | 21 +++ .../JSON/IJsonFeatureElement.cs | 2 + .../JSON/JsonScenario.cs | 2 + .../JSON/JsonScenarioOutline.cs | 2 + ...narioOutlineToJsonScenarioOutlineMapper.cs | 1 + .../Mapper/ScenarioToJsonScenarioMapper.cs | 1 + .../Pickles/Extensions/StringExtensions.cs | 34 +++- src/Pickles/Pickles/ObjectModel/Mapper.cs | 4 + src/Pickles/Pickles/Pickles.csproj | 5 + .../Pickles/Resources/Html/css/structure.css | 7 + .../Pickles/Resources/Html/js/scripts.js | 10 ++ src/Pickles/VersionInfo.cs | 8 +- 33 files changed, 509 insertions(+), 146 deletions(-) create mode 100644 src/Pickles/Pickles.BaseDhtmlFiles/img/link.png create mode 100644 src/Pickles/Pickles.ObjectModel/ObjectModel/ScenarioBase.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 88d8d9ee2..7092a0a65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,12 @@ Features in Experimental are subject to change and removal without being conside This document is formatted according to the principles of [Keep A CHANGELOG](http://keepachangelog.com). +## [2.8.0] - 2016-06-29 + +### Added + +* Hyperlink Feature #1: Automatic Hyperlink Generation for Scenario Titles ([320](https://github.com/picklesdoc/pickles/issues/320)) (by [@ocsurfnut](https://github.com/ocsurfnut)). + ## [2.7.0] - 2016-06-14 ### Added diff --git a/build.bat b/build.bat index ee47b56e3..13be015ae 100644 --- a/build.bat +++ b/build.bat @@ -1,5 +1,5 @@ @echo off -set "picklesVersion=2.7.0" +set "picklesVersion=2.8.0" cls diff --git a/src/Pickles/Pickles.BaseDhtmlFiles/Index.html b/src/Pickles/Pickles.BaseDhtmlFiles/Index.html index ef8794ff9..fefb5c624 100644 --- a/src/Pickles/Pickles.BaseDhtmlFiles/Index.html +++ b/src/Pickles/Pickles.BaseDhtmlFiles/Index.html @@ -1,4 +1,4 @@ - + @@ -14,7 +14,7 @@ - #### EMBED EXPERIMENTALS #### + @@ -173,7 +173,7 @@

Background:

-
+
@@ -195,6 +195,9 @@

+ Get Link for Scenario +

@@ -254,6 +257,25 @@

@NotTested Scenario Summary by Root Namespace

+ ", mathScript); } else { - this.WriteTextFile(folder, "Index.html", "#### EMBED EXPERIMENTALS ####", ""); + this.WriteTextFile(folder, "Index.html", "", ""); } this.WriteTextFile(folder, "pickledFeatures.js"); @@ -65,6 +65,7 @@ public void WriteTo(string folder) this.EnsureFolder(imagesFolder); this.WriteImage(imagesFolder, "glyphicons-halflings-white.png"); this.WriteImage(imagesFolder, "glyphicons-halflings.png"); + this.WriteImage(imagesFolder, "link.png"); string scriptsFolder = this.FileSystem.Path.Combine(folder, "js"); this.EnsureFolder(scriptsFolder); diff --git a/src/Pickles/Pickles/DocumentationBuilders/HTML/HtmlScenarioFormatter.cs b/src/Pickles/Pickles/DocumentationBuilders/HTML/HtmlScenarioFormatter.cs index b6dd41c9c..df1094740 100644 --- a/src/Pickles/Pickles/DocumentationBuilders/HTML/HtmlScenarioFormatter.cs +++ b/src/Pickles/Pickles/DocumentationBuilders/HTML/HtmlScenarioFormatter.cs @@ -50,6 +50,7 @@ public XElement Format(Scenario scenario, int id) var header = new XElement( this.xmlns + "div", new XAttribute("class", "scenario-heading"), + string.IsNullOrEmpty(scenario.Slug) ? null : new XAttribute("id", scenario.Slug), new XElement(this.xmlns + "h2", scenario.Name)); var tags = RetrieveTags(scenario); @@ -72,7 +73,26 @@ public XElement Format(Scenario scenario, int id) new XAttribute("class", "steps"), new XElement( this.xmlns + "ul", - scenario.Steps.Select(step => this.htmlStepFormatter.Format(step))))); + scenario.Steps.Select(step => this.htmlStepFormatter.Format(step)))), + this.FormatLinkButton(scenario)); + } + + private XElement FormatLinkButton(Scenario scenarioOutline) + { + if (string.IsNullOrEmpty(scenarioOutline.Slug)) + { + return null; + } + + return new XElement( + this.xmlns + "a", + new XAttribute("class", "scenario-link"), + new XAttribute("href", $"javascript:showImageLink('{scenarioOutline.Slug}')"), + new XAttribute("title", "Copy scenario link to clipboard."), + new XElement( + this.xmlns + "i", + new XAttribute("class", "icon-link"), + " ")); } internal static XNode[] CreateTagElements(string[] tags, XNamespace xNamespace) diff --git a/src/Pickles/Pickles/DocumentationBuilders/HTML/HtmlScenarioOutlineFormatter.cs b/src/Pickles/Pickles/DocumentationBuilders/HTML/HtmlScenarioOutlineFormatter.cs index 901e9d5fe..8ec8e9058 100644 --- a/src/Pickles/Pickles/DocumentationBuilders/HTML/HtmlScenarioOutlineFormatter.cs +++ b/src/Pickles/Pickles/DocumentationBuilders/HTML/HtmlScenarioOutlineFormatter.cs @@ -61,7 +61,9 @@ private XElement FormatHeading(ScenarioOutline scenarioOutline) var result = new XElement( this.xmlns + "div", new XAttribute("class", "scenario-heading"), + string.IsNullOrEmpty(scenarioOutline.Slug) ? null : new XAttribute("id", scenarioOutline.Slug), new XElement(this.xmlns + "h2", scenarioOutline.Name)); + var tags = RetrieveTags(scenarioOutline); if (tags.Length > 0) { @@ -91,6 +93,24 @@ private XElement FormatSteps(ScenarioOutline scenarioOutline) step => this.htmlStepFormatter.Format(step)))); } + private XElement FormatLinkButton(ScenarioOutline scenarioOutline) + { + if (string.IsNullOrEmpty(scenarioOutline.Slug)) + { + return null; + } + + return new XElement( + this.xmlns + "a", + new XAttribute("class", "scenario-link"), + new XAttribute("href", $"javascript:showImageLink('{scenarioOutline.Slug}')"), + new XAttribute("title", "Copy scenario link to clipboard."), + new XElement( + this.xmlns + "i", + new XAttribute("class", "icon-link"), + " ")); + } + private XElement FormatExamples(ScenarioOutline scenarioOutline) { var exampleDiv = new XElement(this.xmlns + "div"); @@ -117,6 +137,7 @@ public XElement Format(ScenarioOutline scenarioOutline, int id) this.htmlImageResultFormatter.Format(scenarioOutline), this.FormatHeading(scenarioOutline), this.FormatSteps(scenarioOutline), + this.FormatLinkButton(scenarioOutline), (scenarioOutline.Examples == null || !scenarioOutline.Examples.Any()) ? null : this.FormatExamples(scenarioOutline)); diff --git a/src/Pickles/Pickles/DocumentationBuilders/JSON/IJsonFeatureElement.cs b/src/Pickles/Pickles/DocumentationBuilders/JSON/IJsonFeatureElement.cs index 70c47ec91..8330e587d 100644 --- a/src/Pickles/Pickles/DocumentationBuilders/JSON/IJsonFeatureElement.cs +++ b/src/Pickles/Pickles/DocumentationBuilders/JSON/IJsonFeatureElement.cs @@ -28,6 +28,8 @@ public interface IJsonFeatureElement string Name { get; set; } + string Slug { get; set; } + string Description { get; set; } List Steps { get; set; } diff --git a/src/Pickles/Pickles/DocumentationBuilders/JSON/JsonScenario.cs b/src/Pickles/Pickles/DocumentationBuilders/JSON/JsonScenario.cs index 997893b9f..6c2f92037 100644 --- a/src/Pickles/Pickles/DocumentationBuilders/JSON/JsonScenario.cs +++ b/src/Pickles/Pickles/DocumentationBuilders/JSON/JsonScenario.cs @@ -35,6 +35,8 @@ public JsonScenario() public string Name { get; set; } + public string Slug { get; set; } + public string Description { get; set; } public List Steps { get; set; } diff --git a/src/Pickles/Pickles/DocumentationBuilders/JSON/JsonScenarioOutline.cs b/src/Pickles/Pickles/DocumentationBuilders/JSON/JsonScenarioOutline.cs index 43c62a6f5..cdf018318 100644 --- a/src/Pickles/Pickles/DocumentationBuilders/JSON/JsonScenarioOutline.cs +++ b/src/Pickles/Pickles/DocumentationBuilders/JSON/JsonScenarioOutline.cs @@ -37,6 +37,8 @@ public JsonScenarioOutline() public string Name { get; set; } + public string Slug { get; set; } + public string Description { get; set; } public List Steps { get; set; } diff --git a/src/Pickles/Pickles/DocumentationBuilders/JSON/Mapper/ScenarioOutlineToJsonScenarioOutlineMapper.cs b/src/Pickles/Pickles/DocumentationBuilders/JSON/Mapper/ScenarioOutlineToJsonScenarioOutlineMapper.cs index fff685b98..118e667ec 100644 --- a/src/Pickles/Pickles/DocumentationBuilders/JSON/Mapper/ScenarioOutlineToJsonScenarioOutlineMapper.cs +++ b/src/Pickles/Pickles/DocumentationBuilders/JSON/Mapper/ScenarioOutlineToJsonScenarioOutlineMapper.cs @@ -50,6 +50,7 @@ public JsonScenarioOutline Map(ScenarioOutline scenarioOutline) Steps = (scenarioOutline.Steps ?? new List()).Select(this.stepMapper.Map).ToList(), Tags = (scenarioOutline.Tags ?? new List()).ToList(), Name = scenarioOutline.Name, + Slug = scenarioOutline.Slug, Description = scenarioOutline.Description, Result = this.resultMapper.Map(scenarioOutline.Result), }; diff --git a/src/Pickles/Pickles/DocumentationBuilders/JSON/Mapper/ScenarioToJsonScenarioMapper.cs b/src/Pickles/Pickles/DocumentationBuilders/JSON/Mapper/ScenarioToJsonScenarioMapper.cs index 57d996c5f..a52a7b8cd 100644 --- a/src/Pickles/Pickles/DocumentationBuilders/JSON/Mapper/ScenarioToJsonScenarioMapper.cs +++ b/src/Pickles/Pickles/DocumentationBuilders/JSON/Mapper/ScenarioToJsonScenarioMapper.cs @@ -49,6 +49,7 @@ public JsonScenario Map(Scenario scenario) Steps = (scenario.Steps ?? new List()).Select(this.stepMapper.Map).ToList(), Tags = (scenario.Tags ?? new List()).ToList(), Name = scenario.Name, + Slug = scenario.Slug, Description = scenario.Description, Result = this.resultMapper.Map(scenario.Result), }; diff --git a/src/Pickles/Pickles/Extensions/StringExtensions.cs b/src/Pickles/Pickles/Extensions/StringExtensions.cs index 9734df3d1..68509524f 100644 --- a/src/Pickles/Pickles/Extensions/StringExtensions.cs +++ b/src/Pickles/Pickles/Extensions/StringExtensions.cs @@ -24,6 +24,8 @@ namespace PicklesDoc.Pickles.Extensions { + using System.Text.RegularExpressions; + public static class StringExtensions { public static string ExpandWikiWord(this string word) @@ -32,8 +34,8 @@ public static string ExpandWikiWord(this string word) char previous = char.MinValue; foreach (char current in word.Where(x => char.IsLetterOrDigit(x))) { - if (previous != char.MinValue && sb.Length > 1 && - ((char.IsUpper(current) || char.IsDigit(current)) && char.IsLower(previous))) + if (previous != char.MinValue && sb.Length > 1 + && ((char.IsUpper(current) || char.IsDigit(current)) && char.IsLower(previous))) { sb.Append(' '); } @@ -57,8 +59,32 @@ public static string ExpandWikiWord(this string word) public static string ComparisonNormalize(this string text) { return - text.Trim().ToLowerInvariant().Replace("\r", string.Empty).Replace("\n", Environment.NewLine).Replace( - "\t", " "); + text.Trim() + .ToLowerInvariant() + .Replace("\r", string.Empty) + .Replace("\n", Environment.NewLine) + .Replace("\t", " "); + } + + /// + /// Takes a string and returns a url-friendly version of the string (slug) with all special characters + /// and extra spaces stripped out, with words seperated by dashes. + /// + /// The string that will be used to create the slug. + /// A slug generated from the given string. + public static string ToSlug(this string text) + { + // remove any accent characters + var bytes = Encoding.GetEncoding("Cyrillic").GetBytes(text); + var str = Encoding.ASCII.GetString(bytes); + + // modify string to slug format + str = str.ToLower(); + str = Regex.Replace(str, @"[^a-z0-9\s-]", ""); + str = Regex.Replace(str, @"\s+", " ").Trim(); + str = Regex.Replace(str, @"\s", "-"); + + return str; } } } diff --git a/src/Pickles/Pickles/ObjectModel/Mapper.cs b/src/Pickles/Pickles/ObjectModel/Mapper.cs index c87b893fe..3687feb28 100644 --- a/src/Pickles/Pickles/ObjectModel/Mapper.cs +++ b/src/Pickles/Pickles/ObjectModel/Mapper.cs @@ -25,6 +25,8 @@ namespace PicklesDoc.Pickles.ObjectModel { + using PicklesDoc.Pickles.Extensions; + public class Mapper { private readonly IConfiguration configuration; @@ -172,6 +174,7 @@ public Scenario MapToScenario(G.Scenario scenario) Description = scenario.Description ?? string.Empty, Location = this.MapToLocation(scenario.Location), Name = scenario.Name, + Slug = scenario.Name.ToSlug(), Steps = scenario.Steps.Select(this.MapToStep).ToList(), Tags = scenario.Tags.Select(this.MapToString).ToList() }; @@ -205,6 +208,7 @@ public ScenarioOutline MapToScenarioOutline(G.ScenarioOutline scenarioOutline) Examples = (scenarioOutline.Examples ?? new G.Examples[0]).Select(this.MapToExample).ToList(), Location = this.MapToLocation(scenarioOutline.Location), Name = scenarioOutline.Name, + Slug = scenarioOutline.Name.ToSlug(), Steps = scenarioOutline.Steps.Select(this.MapToStep).ToList(), Tags = scenarioOutline.Tags.Select(this.MapToString).ToList() }; diff --git a/src/Pickles/Pickles/Pickles.csproj b/src/Pickles/Pickles/Pickles.csproj index 220d4f32b..db9414817 100644 --- a/src/Pickles/Pickles/Pickles.csproj +++ b/src/Pickles/Pickles/Pickles.csproj @@ -349,6 +349,11 @@ Resources\Dhtml\js\knockout-3.4.0.js + + + Resources\Dhtml\img\link.png + +