diff --git a/src/Pretzel.Logic/Commands/CommandParameters.cs b/src/Pretzel.Logic/Commands/CommandParameters.cs index b02758308..d1c63e631 100644 --- a/src/Pretzel.Logic/Commands/CommandParameters.cs +++ b/src/Pretzel.Logic/Commands/CommandParameters.cs @@ -35,7 +35,8 @@ public CommandParameters([ImportMany] IEnumerable commandL { "nobrowser", "Do not launch a browser", v => LaunchBrowser = false }, { "withproject", "Includes a layout VS Solution, to give intellisense when editing razor layout files", v => WithProject = (v!=null) }, { "wiki", "Creates a wiki instead of a blog (razor template only)", v => Wiki = (v!=null) }, - { "cleantarget", "Delete the target directory (_site by default)", v => CleanTarget = true } + { "cleantarget", "Delete the target directory (_site by default)", v => CleanTarget = true }, + { "n|newposttitle=", "The title of the new post (\"New post\" by default)", v => NewPostTitle = v } }; // Allow extensions to register command line args @@ -66,6 +67,8 @@ public CommandParameters([ImportMany] IEnumerable commandL public string DestinationPath { get; private set; } + public string NewPostTitle { get; internal set; } + private decimal port; public decimal Port @@ -91,6 +94,10 @@ public void Parse(IEnumerable arguments) { DestinationPath = fileSystem.Path.Combine(Path, DestinationPath); } + if (string.IsNullOrEmpty(NewPostTitle)) + { + NewPostTitle = "New post"; + } } public void DetectFromDirectory(IDictionary engines, SiteContext context) diff --git a/src/Pretzel.Logic/Pretzel.Logic.csproj b/src/Pretzel.Logic/Pretzel.Logic.csproj index d335c9430..fb8f63f96 100644 --- a/src/Pretzel.Logic/Pretzel.Logic.csproj +++ b/src/Pretzel.Logic/Pretzel.Logic.csproj @@ -168,6 +168,7 @@ True Resources.resx + diff --git a/src/Pretzel.Logic/Recipe/Ingredient.cs b/src/Pretzel.Logic/Recipe/Ingredient.cs new file mode 100644 index 000000000..4a5d6966d --- /dev/null +++ b/src/Pretzel.Logic/Recipe/Ingredient.cs @@ -0,0 +1,50 @@ +using System; +using System.IO.Abstractions; +using Pretzel.Logic.Extensibility.Extensions; +using Pretzel.Logic.Extensions; + +namespace Pretzel.Logic.Recipe +{ + public class Ingredient + { + private readonly string directory; + + private readonly IFileSystem fileSystem; + + private readonly string title; + + private readonly bool withDrafts; + + public Ingredient(IFileSystem fileSystem, string title, string directory, bool withDrafts) + { + this.fileSystem = fileSystem; + this.title = title; + this.directory = directory; + this.withDrafts = withDrafts; + } + + public void Create() + { + var postPath = fileSystem.Path.Combine(directory, !this.withDrafts ? @"_posts" : @"_drafts"); + + var postName = string.Format("{0}-{1}.md", DateTime.Today.ToString("yyyy-MM-dd"), SlugifyFilter.Slugify(title)); + var pageContents = string.Format("---\r\n layout: post \r\n title: {0}\r\n comments: true\r\n---\r\n", title); + + if (!fileSystem.Directory.Exists(postPath)) + { + Tracing.Info(string.Format("{0} folder not found", postPath)); + return; + } + + if (fileSystem.File.Exists(fileSystem.Path.Combine(postPath, postName))) + { + Tracing.Info(string.Format("The \"{0}\" file already exists", postName)); + return; + } + + fileSystem.File.WriteAllText(fileSystem.Path.Combine(postPath, postName), pageContents); + + Tracing.Info(string.Format("Created the \"{0}\" post ({1})", title, postName)); + } + } +} \ No newline at end of file diff --git a/src/Pretzel.Tests/Commands/CommandParameterTests.cs b/src/Pretzel.Tests/Commands/CommandParameterTests.cs index 97513697f..bb39a4b0e 100644 --- a/src/Pretzel.Tests/Commands/CommandParameterTests.cs +++ b/src/Pretzel.Tests/Commands/CommandParameterTests.cs @@ -22,6 +22,7 @@ public class CommandParameterTests private const string ExpectedPort = "8000"; private const decimal ExpectedPortDecimal = 8000; private const string ExpectedDestinationPath = @"D:\Code\Generated"; + private const string ExpectedNewPostTitle = @"Post title"; private readonly IFileSystem FileSystem = new MockFileSystem(); @@ -236,6 +237,38 @@ public void LaunchBrowser_WhenNotSpecifyingCleanTarget_IsFalse() Assert.False(subject.CleanTarget); } + [Fact] + public void Parse_WhenSpecifyingNewPostTitleUsingShortParameter_MapsToPath() + { + var args = new List { "--n", ExpectedNewPostTitle }; + subject.Parse(args); + Assert.Equal(ExpectedNewPostTitle, subject.NewPostTitle); + } + + [Fact] + public void Parse_WhenSpecifyingNewPostTitleUsingFullParameter_MapsToPath() + { + var args = new List { "--newposttitle", ExpectedNewPostTitle }; + subject.Parse(args); + Assert.Equal(ExpectedNewPostTitle, subject.NewPostTitle); + } + + [Fact] + public void Parse_WhenSpecifyingNewPostTitleUsingShortParameterSingleDash_MapsToPath() + { + var args = new List { "-n", ExpectedNewPostTitle }; + subject.Parse(args); + Assert.Equal(ExpectedNewPostTitle, subject.NewPostTitle); + } + + [Fact] + public void Parse_WhenSpecifyingNewPostTitleUsingFullParameterSingleDash_MapsToPath() + { + var args = new List { "-newposttitle", ExpectedNewPostTitle }; + subject.Parse(args); + Assert.Equal(ExpectedNewPostTitle, subject.NewPostTitle); + } + [Fact] public void CommandParameters_WhenSpecifyingAllParameters_ResultIsCorrect() { @@ -410,5 +443,13 @@ public void Parse_WhenNoParametersSet_MapsDestinationPathTo_siteInCurrentDirecto subject.Parse(args); Assert.Equal(FileSystem.Path.Combine(subject.Path, "_site"), subject.DestinationPath); } + + [Fact] + public void Parse_WhenNoParametersSet_MapsNewPostTileToNewPost() + { + var args = new List(); + subject.Parse(args); + Assert.Equal("New post", subject.NewPostTitle); + } } } diff --git a/src/Pretzel.Tests/Pretzel.Tests.csproj b/src/Pretzel.Tests/Pretzel.Tests.csproj index 5f9d57dee..976957424 100644 --- a/src/Pretzel.Tests/Pretzel.Tests.csproj +++ b/src/Pretzel.Tests/Pretzel.Tests.csproj @@ -106,6 +106,7 @@ + diff --git a/src/Pretzel.Tests/Recipe/IngredientTests.cs b/src/Pretzel.Tests/Recipe/IngredientTests.cs new file mode 100644 index 000000000..422289459 --- /dev/null +++ b/src/Pretzel.Tests/Recipe/IngredientTests.cs @@ -0,0 +1,97 @@ +using NSubstitute; +using Pretzel.Logic.Extensibility; +using Pretzel.Logic.Extensibility.Extensions; +using Pretzel.Logic.Extensions; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.IO.Abstractions; +using System.IO.Abstractions.TestingHelpers; +using System.Linq; +using System.Text; +using System.Threading; +using Xunit; +using Xunit.Extensions; + +namespace Pretzel.Tests.Recipe +{ + public class IngredientTests + { + private MockFileSystem fileSystem = new MockFileSystem(new Dictionary()); + private const string BaseSite = @"c:\site\"; + private const string PostsFolder = @"_posts"; + private const string DraftsFolder = @"_drafts"; + + private readonly StringBuilder sb = new StringBuilder(); + private readonly TextWriter writer; + + public IngredientTests() + { + writer = new StringWriter(sb); + Tracing.Logger.SetWriter(writer); + Tracing.Logger.AddCategory(Tracing.Category.Info); + Tracing.Logger.AddCategory(Tracing.Category.Error); + Tracing.Logger.AddCategory(Tracing.Category.Debug); + } + + [Fact] + public void Post_Is_Created() + { + fileSystem.Directory.CreateDirectory(BaseSite + PostsFolder); + var postTitle = "Post title"; + var postName = string.Format("{0}-{1}.md", DateTime.Today.ToString("yyyy-MM-dd"), SlugifyFilter.Slugify(postTitle)); + + var ingredient = new Logic.Recipe.Ingredient(fileSystem, postTitle, BaseSite, false); + ingredient.Create(); + + Assert.True(fileSystem.File.Exists(fileSystem.Path.Combine(BaseSite + PostsFolder, postName))); + } + + [Fact] + public void Post_Has_Correct_Content() + { + fileSystem.Directory.CreateDirectory(BaseSite + PostsFolder); + var postTitle = "Post title"; + var expectedContent = string.Format("---\r\n layout: post \r\n title: {0}\r\n comments: true\r\n---\r\n", postTitle); + var postName = string.Format("{0}-{1}.md", DateTime.Today.ToString("yyyy-MM-dd"), SlugifyFilter.Slugify(postTitle)); + + var ingredient = new Logic.Recipe.Ingredient(fileSystem, "Post title", BaseSite, false); + ingredient.Create(); + + Assert.Equal(expectedContent, fileSystem.File.ReadAllText(fileSystem.Path.Combine(BaseSite + PostsFolder, postName))); + } + + [Fact] + public void Post_Already_Exists() + { + fileSystem.Directory.CreateDirectory(BaseSite + PostsFolder); + var postTitle = "Post title"; + var postName = string.Format("{0}-{1}.md", DateTime.Today.ToString("yyyy-MM-dd"), SlugifyFilter.Slugify(postTitle)); + + var ingredient = new Logic.Recipe.Ingredient(fileSystem, postTitle, BaseSite, false); + ingredient.Create(); + ingredient.Create(); + + Assert.Contains(string.Format("The \"{0}\" file already exists", postName), writer.ToString()); + } + + [Fact] + public void Post_Folder_Not_Found() + { + var ingredient = new Logic.Recipe.Ingredient(fileSystem, string.Empty, BaseSite, false); + ingredient.Create(); + + Assert.Contains(string.Format(@"{0} folder not found", BaseSite + PostsFolder), writer.ToString()); + } + + [Fact] + public void Draft_Folder_Not_Found() + { + var ingredient = new Logic.Recipe.Ingredient(fileSystem, string.Empty, BaseSite, true); + ingredient.Create(); + + Assert.Contains(string.Format(@"{0} folder not found", BaseSite + DraftsFolder), writer.ToString()); + } + } +} diff --git a/src/Pretzel/Commands/IngredientCommand.cs b/src/Pretzel/Commands/IngredientCommand.cs new file mode 100644 index 000000000..dcf4490c1 --- /dev/null +++ b/src/Pretzel/Commands/IngredientCommand.cs @@ -0,0 +1,41 @@ +using Pretzel.Logic.Commands; +using Pretzel.Logic.Extensions; +using Pretzel.Logic.Recipe; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using System.IO.Abstractions; + +namespace Pretzel.Commands +{ + [PartCreationPolicy(CreationPolicy.Shared)] + [CommandInfo(CommandName = "ingredient")] + public sealed class IngredientCommand : ICommand + { +#pragma warning disable 649 + + [Import] + private IFileSystem fileSystem; + + [Import] + private CommandParameters parameters; + +#pragma warning restore 649 + + public void Execute(IEnumerable arguments) + { + Tracing.Info("ingredient - create a new post"); + + parameters.Parse(arguments); + + var ingredient = new Ingredient(fileSystem, parameters.NewPostTitle, parameters.Path, parameters.IncludeDrafts); + ingredient.Create(); + } + + public void WriteHelp(TextWriter writer) + { + writer.Write(" Create a new post\r\n"); + parameters.WriteOptions(writer, "newposttitle", "drafts", "-s"); + } + } +} \ No newline at end of file diff --git a/src/Pretzel/Pretzel.csproj b/src/Pretzel/Pretzel.csproj index 974579d05..5b4fdb228 100644 --- a/src/Pretzel/Pretzel.csproj +++ b/src/Pretzel/Pretzel.csproj @@ -132,6 +132,7 @@ +