Skip to content

Conversation

@egoughnour
Copy link
Contributor

@egoughnour egoughnour commented Sep 12, 2017

This change allows multiple input XML files and also merging of existing (manually maintained) markdown files. Added a test project for the MSBuild task. The AfterBuild target in .targets file is reduced to two steps:

  1. Warn if XML documentation isn't enabled.
  2. GenerateMarkdown task.

It also resolves #16.
Tested with RhinoMocks and MSTest. Also tested the .nupkg file in VS.

Added Task.  Included file merge also.
added mock build engine and real TaskItem instances to a test on the new task.
Added custom task to .targets file.  Removed redundant elements of target.
updated nuspec.   Should point files back to tools directory though.
slight changes to paths.
This file is generated during build.  Not needed.
Generated during build.  Not needed.
mentions build task.
updated nuspec and  updated assembly info on both msbuild task and executable.
added flag for msbuild task.  warn rather than error when set to true and unexpected tag is encountered.
@egoughnour
Copy link
Contributor Author

Resolves #12. Manually tested and in unit tests.

@egoughnour egoughnour closed this Sep 12, 2017
@egoughnour
Copy link
Contributor Author

Accidentally closed PR.

@egoughnour egoughnour reopened this Sep 12, 2017
@Pxtl
Copy link
Owner

Pxtl commented Oct 25, 2017

Sorry, I've been off GH for a bit. This is really cool and is a lot to take in... if I'm reading this right, though, won't it break for existing users? If they don't have a readme.md in their project today it won't find it and it will error out.

@egoughnour
Copy link
Contributor Author

Yeah--it probably needs the default functionality to handle all existing use cases without failure and without reconfiguration. I'd have to look at it for a second to see whether that's what would happen.

@egoughnour
Copy link
Contributor Author

It looks like the only potential issue would be updating the NuGet package in projects where it is already installed.
I am not sure what can be done in terms of detecting this situation (possibly in PowerShell).
If there is a way to support detection of update (as opposed to clean install) then I would not mind to add some PowerShell to do it. (I am also unsure if this additional change should include pester tests along with whatever modules and scripts, but I am okay with making this happen.)

@Pxtl
Copy link
Owner

Pxtl commented Oct 26, 2017

I would be very tempted to make the "merge" functionality politely ignore the absense of the readme file. You'd still have the small breakage of existing users that their XmlDoc would now contain their Readme files, but you wouldn't have existing users seeing the project break for them.

I've been looking into how to make this configurable - there's not much documentation on Nuget build/.targets and build/.props files, but it looks like .props aren't user friendly and are a bit coarse.

I wouldn't want to include breaking functionality without an ability to turn it off.

@egoughnour
Copy link
Contributor Author

Suppressing some of the build tasks might work.
Forcing open release notes in a text file is possible with nuget.
So maybe the key is to explain the on/off functionality in a small set of release notes (that the user can't avoid).
Users could set a specific value of the CustomAfterMicrosoftCommonTargets property.
This would be the path to another .proj or .props or .targets file included in the content of the nuget package but otherwise unused.

Turn that on and you get whatever functionality you want rather than the default.

Heck, there could be 3 or 4 alternative project files--supposing there are actually that many viable choices.

@egoughnour
Copy link
Contributor Author

egoughnour commented Oct 27, 2017

And by a small set of notes I mean something like:

Don't like the default build output? Paste one of the following into your project file as an attribute under <MSBuild (or whichever tag would actually make sense).

  • Properties="CustomAfterMicrosoftCommonTargets=..\..\..\packages\<...>\OptionA.csproj"
    when generating Markdown, include only the files specified in OptionA.csproj

  • Properties="CustomAfterMicrosoftCommonTargets=..\..\..\packages\<...>\OptionB.proj"
    When Generating Markdown, exclude the .xml files in OptionB.proj or in the specified directory

  • Properties="CustomAfterMicrosoftCommonTargets=..\..\..\packages\<...>\OptionC.csproj"
    Some other combination of options.

@Pxtl
Copy link
Owner

Pxtl commented Oct 27, 2017

I'm not sure I'd want users to be forced to edit the .csproj file since it's such an opaque mess, but I know that's the way this is supposed to be done and the future of this stuff. It's too bad there's no way to apply XML comments at the Assembly level (only to classes/props/etc.) or I'd say put the config there - an assembly-level Readme.md would've been good.

It's tempting just to create a XmlCommentMarkdownGenerator.Config.xml (or json, as you like it) at the root of the target project and just keep settings there... but that seems less idiomatic than just editing the .csproj.

Or we could put YAML front-matter in the project's readme.md for parameters, Jekyll-style. It's pretty standard approach, but it would mean a bunch of YAML crap in the HTML view if you opened the readme.md

Like start the readme.md with

---
MergeXmlComments: true
AllowedCustomTags: all
---

And assume the user wants to not merge the readme if that block is missing.

@egoughnour
Copy link
Contributor Author

Okay. Using front-matter makes sense and it's a frequently used pattern. I'll add a commit or two to handle it.

A couple items of note:
 - Code52/pretzel is  a partial .NET implementation of Jekyll.
 - Process() apparently is always called.
 - CanProcess() is only called as needed based on the file timestamps.
 - After the custom tag check, the MD file merging should occur.
 - `pretzel taste` may need some try/catch or other handling.
Below is the output when run against my test content:

```
>pretzel taste -t=customxmlmd
starting pretzel...
taste - testing a site locally
About to check CanProcess(context) again
about to check 'mergexmlcomments' a bool
as boolean 'mergexmlcomments' is true
Custom Tag to allow: all

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
   at Pretzel.Logic.Minification.LessTransform.<Transform>b__5_0(Page p)
   at System.Linq.Enumerable.WhereListIterator`1.MoveNext()
   at Pretzel.Logic.Minification.LessTransform.Transform(SiteContext siteContext)
   at Pretzel.Commands.TasteCommand.Execute(IEnumerable`1 arguments)
   at Pretzel.Program.Run(BaseParameters baseParameters)
   at Pretzel.Program.Main(String[] args)
```
These values are read by the custom plugin.
@egoughnour
Copy link
Contributor Author

egoughnour commented Oct 29, 2017

Bad News/Good News

Currently

  • the exception handling isn't in place for the liquid templating. Avoiding exception-related complexity with Environment.Exit(0) in the plugin itself.

  • the actual call for markdown merging hasn't been added in the custom plugin/processor (and it won't be. see updated plan below.)

  • the custom processing works fine

  • the front matter is being read in testing

  • additional template processing can be added

  • this has already been tested with Pretzel and Pretzel.ScriptCs.

  • Pretzel is compatible with Jekyll.

  • It is simple to add pretzel into the nuget package and simply invoke it from the build.

@egoughnour
Copy link
Contributor Author

Using the Pretzel Adapter

  • Create WIX installer for adapter

  • Create Chocolatey package from installer and pretzel and pretzel.scriptcs dependencies

  • MSBuild task can either pull the front matter directly or the choco install can set up a pretzel instance for more complicated scenarios. This also enables forward compatibility once Jekyll or the WSL advances enough for a full auto Jekyll on windows nuget package to be feasible.

@Pxtl
Copy link
Owner

Pxtl commented Oct 30, 2017

Ooooof, can Pretzel is far too big of a dependency. I hate to keep poo-pooing this great work you're doing, but that's overkill. Detect the opening "---", then find the next line that starts with "---", and apply a YAML parser to everything in between to pull out the config fields.

@egoughnour
Copy link
Contributor Author

Alright. I’ll go with pull the front matter directly.

@egoughnour
Copy link
Contributor Author

Tested.

Copy link
Owner

@Pxtl Pxtl left a comment

Choose a reason for hiding this comment

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

Looks good - there's a bit of naming I don't like, and some Pretzel stuff is still there.

I'm mostly concerned about getting the public file config API right so that users don't have to deal with that churning if we have to refactor later.

Thanks for doing so much on this, it looks great.

@@ -0,0 +1,60 @@
using Pretzel.Logic.Templating;
Copy link
Owner

Choose a reason for hiding this comment

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

Is this file still being used? I thought the new workflow got rid of this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • No, not used.
  • Yes, it has been gotten rid of.
  • The delete didn't get committed apparently.

@@ -0,0 +1,20 @@
---
Copy link
Owner

Choose a reason for hiding this comment

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

Ditto, more Pretzel stuff here.

using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;
Copy link
Owner

Choose a reason for hiding this comment

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

remove commented code.

/// Defaults to false. When true unexpected tags in the documentation
/// will generate warnings rather than errors.
/// </summary>
public bool WarnOnUnexpectedTag { get; set; } = false;
Copy link
Owner

Choose a reason for hiding this comment

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

The inconsistent naming between the Enum, the Bool, and the Enum type itself is problematic but I'd rather just put this in and refactor that later.

/// <summary>
/// The file to be created by the merge. Unused if MergeFiles evaluates to false.
/// </summary>
public ITaskItem OutputFile { get; set; }
Copy link
Owner

Choose a reason for hiding this comment

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

Because it's so tightly tied to MergeFiles behavior, rename to MergedOutputFile. Doubly confusing because you also have an OutputPath property below that has a completely unrelated behavior.

@@ -0,0 +1,273 @@
using System;
Copy link
Owner

Choose a reason for hiding this comment

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

General problem in this file: You have 3 config paths. InputXml (an array of paths to XML files), DocumentationPath (a path to a markdown file or folder) and OutputFile (a path to the output file to be created). This naming is very inconsistent - they're all paths (although the Input and Output ones are to a file while DocumentationPath is permitted to be a folder). Also, DocumentationPath wears two hats - it's both the folder the pre-merged documentation gets written to and the folder where the MD files get output to before they merged into the single giant MD document. Many projects have their readmes stored outside of the ./Docs folder, and so it would make sense to have those feed into the ./Docs folder output.

Imho, split the documentation path into two folders.

Clearer naming would also definitely help. My recommendations:

InputMdDocumentationPath,
OutputMdDocumentationPath,
MergedOutputFilePath,
InputXmlFilePaths.

I prefer clear verbosity to terse ambiguity.

Also, I'm looking at the behavior here: it looks like if the DocumentationPath is a file and merge is off, it will read from that file to get parameters, and then replace the body of that file with the generated documentation. That seems bad - really highlights the need to separate the input DocumentationPath and the output one.


/// <summary>
/// DocumentationPath is the top level directory in which to search for files.
/// It is also the path where generated markdown files are created.
Copy link
Owner

@Pxtl Pxtl Nov 2, 2017

Choose a reason for hiding this comment

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

This comment highlights the problem of how DocumentationPath wears two hats - it does not make sense that the header docs must be present in the same ./Docs folder they're going to get merged into.

GenerateFiles();
if (MergeFiles)
{
Merge();
Copy link
Owner

Choose a reason for hiding this comment

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

Shouldn't there be a separate CreateDirectoryIfNeeded for outputfile because it's possible that the merged outputfile is outside of documentation path?

var mdFiles = Directory.EnumerateFiles(DocumentationPath.ItemSpec, "*.md", SearchOption.AllDirectories).ToList();
foreach (var mdFile in mdFiles)
{
if (TryGetFrontMatter(mdFile, out string frontMatter, out bool isEmpty) &&
Copy link
Owner

Choose a reason for hiding this comment

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

I'm not fond of the fact that it does this in apparently undefined order isntead of looking for an .md file that matches the XML file by name first, or look fora file named readme.md first... but either way, it's good for now. This looks like an opportunity for future enhancement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Is there a way to put the output somewhere different?

2 participants