diff --git a/src/CloudNimble.DotNetDocs.Mintlify/MintlifyRenderer.cs b/src/CloudNimble.DotNetDocs.Mintlify/MintlifyRenderer.cs index 431e563..8b6902f 100644 --- a/src/CloudNimble.DotNetDocs.Mintlify/MintlifyRenderer.cs +++ b/src/CloudNimble.DotNetDocs.Mintlify/MintlifyRenderer.cs @@ -76,7 +76,7 @@ public async Task RenderAsync(DocAssembly model) ArgumentNullException.ThrowIfNull(model); var apiOutputPath = Path.Combine(Context.DocumentationRootPath, Context.ApiReferencePath); - Console.WriteLine($"📝 Rendering documentation to: {apiOutputPath}"); + // Console.WriteLine($"📝 Rendering documentation to: {apiOutputPath}"); // Initialize DocsJsonManager if enabled (only on first call) DocsJsonConfig? docsConfig = null; @@ -1501,7 +1501,7 @@ private async Task GenerateNamespacePlaceholdersAsync(DocNamespace ns, string co var namespacePath = Context.GetNamespaceFolderPath(ns.Name ?? "global"); var namespaceDir = Path.Combine(conceptualPath, namespacePath); - Console.WriteLine($"📝 Generating namespace placeholders for: {ns.Name} at {namespaceDir}"); + // Console.WriteLine($"📝 Generating namespace placeholders for: {ns.Name} at {namespaceDir}"); Directory.CreateDirectory(namespaceDir); // Generate individual placeholder files diff --git a/src/CloudNimble.DotNetDocs.Sdk.Tasks/CloudNimble.DotNetDocs.Sdk.Tasks.csproj b/src/CloudNimble.DotNetDocs.Sdk.Tasks/CloudNimble.DotNetDocs.Sdk.Tasks.csproj deleted file mode 100644 index 72ebe93..0000000 --- a/src/CloudNimble.DotNetDocs.Sdk.Tasks/CloudNimble.DotNetDocs.Sdk.Tasks.csproj +++ /dev/null @@ -1,54 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net472 - false - MSBuild tasks for CloudNimble.DotNetDocs.Sdk - - - false - false - - - $(NoWarn);CS2008;NU1701 - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/CloudNimble.DotNetDocs.Sdk.Tasks/DiscoverDocumentedProjectsTask.cs b/src/CloudNimble.DotNetDocs.Sdk.Tasks/DiscoverDocumentedProjectsTask.cs deleted file mode 100644 index db8326e..0000000 --- a/src/CloudNimble.DotNetDocs.Sdk.Tasks/DiscoverDocumentedProjectsTask.cs +++ /dev/null @@ -1,302 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using CloudNimble.EasyAF.Core; -using Microsoft.Build.Evaluation; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; - -namespace CloudNimble.DotNetDocs.Sdk.Tasks -{ - - /// - /// MSBuild task that discovers which projects in a solution should be documented based on their MSBuild properties. - /// - public class DiscoverDocumentedProjectsTask : Task - { - - #region Fields - - internal Dictionary _propertiesToEvaluate = new() - { - { "IsTestProject", false }, // Exclude test projects - { "IsPackable", true }, // Include only packable projects (default is true) - { "ExcludeFromDocumentation", false } // Exclude projects explicitly marked to be excluded - }; - - #endregion - - #region Properties - - /// - /// Gets or sets the solution directory to search for projects. - /// - [Required] - public string SolutionDir { get; set; } = string.Empty; - - /// - /// Gets or sets the configuration to use when evaluating projects. - /// - public string Configuration { get; set; } = "Release"; - - /// - /// Gets or sets the target framework to use when evaluating projects. - /// - public string TargetFramework { get; set; } = "net8.0"; - - /// - /// Gets or sets the exclude patterns for projects that should not be documented. - /// - public string[]? ExcludePatterns { get; set; } - - /// - /// Gets or sets the discovered projects that should be documented. - /// - [Output] - public ITaskItem[] DocumentedProjects { get; set; } = []; - - #endregion - - #region Public Methods - - /// - /// Executes the task to discover documented projects. - /// - /// true if the task executed successfully; otherwise, false. - public override bool Execute() - { - try - { - Log.LogMessage(MessageImportance.High, $"🔍 Discovering documented projects in {SolutionDir}..."); - - var documentedProjects = new List(); - - // Search for all .NET project file types and filter out excluded patterns - var projectExtensions = new[] { "*.csproj", "*.vbproj", "*.fsproj" }; - var projectFiles = projectExtensions - .SelectMany(ext => Directory.GetFiles(SolutionDir, ext, SearchOption.AllDirectories)) - .Where(file => ExcludePatterns is null || !ExcludePatterns.Any(pattern => - Path.GetFileNameWithoutExtension(file).Contains(pattern.Replace("*", ""), StringComparison.OrdinalIgnoreCase))) - .ToArray(); - - var projectCollection = new ProjectCollection(); - - // Set up global properties for evaluation - var globalProperties = new Dictionary - { - { "Configuration", Configuration } - }; - - foreach (var projectFile in projectFiles) - { - var projectName = Path.GetFileNameWithoutExtension(projectFile); - - try - { - // Create an evaluated project to get computed property values - var project = new Project(projectFile, globalProperties, null, projectCollection); - - try - { - - bool shouldSkip = false; - foreach (var prop in _propertiesToEvaluate) - { - var propValue = project.GetPropertyValue(prop.Key); - if (string.Equals(propValue, "true", StringComparison.OrdinalIgnoreCase) != prop.Value) - { - Log.LogMessage(MessageImportance.Low, $" ⏭️ Skipping project {projectName} due to property {prop.Key}={propValue}"); - shouldSkip = true; - break; - } - } - if (shouldSkip) - { - continue; // Skip to next project - } - - // This is a project we should document - var item = new TaskItem(projectFile); - - // Set metadata from the evaluated project - var assemblyName = project.GetPropertyValue("AssemblyName"); - if (string.IsNullOrEmpty(assemblyName)) - { - assemblyName = projectName; - } - - var targetFramework = project.GetPropertyValue("TargetFramework"); - if (string.IsNullOrEmpty(targetFramework)) - { - // For multi-targeted projects, use TargetFrameworks and pick the first one - var targetFrameworks = project.GetPropertyValue("TargetFrameworks"); - if (!string.IsNullOrEmpty(targetFrameworks)) - { - targetFramework = targetFrameworks.Split(';')[0].Trim(); - } - else - { - targetFramework = TargetFramework; // Use default - } - } - - item.SetMetadata("AssemblyName", assemblyName); - item.SetMetadata("OutputPath", $"bin\\{Configuration}"); - item.SetMetadata("TargetFramework", targetFramework); - item.SetMetadata("TargetPath", $"bin\\{Configuration}\\{targetFramework}\\{assemblyName}.dll"); - - documentedProjects.Add(item); - Log.LogMessage(MessageImportance.High, $" ✅ Found packable project: {projectName}"); - } - finally - { - // Always unload the project to free resources - projectCollection.UnloadProject(project); - } - } - catch (Exception ex) - { - Log.LogWarning($"Could not evaluate project {projectFile}: {ex.Message}"); - } - } - - // Clean up the project collection - projectCollection.UnloadAllProjects(); - - DocumentedProjects = [.. documentedProjects]; - Log.LogMessage(MessageImportance.High, $"📊 Found {DocumentedProjects.Length} documented projects"); - - return true; - } - catch (Exception ex) - { - Log.LogError($"Failed to discover documented projects: {ex.Message}"); - return false; - } - } - - #endregion - - #region Internal Methods - - /// - /// Discovers project files in the specified directory. - /// - /// The solution directory to search. - /// Patterns to exclude from discovery. - /// Array of discovered project file paths. - internal string[] DiscoverProjectFiles(string solutionDir, string[]? excludePatterns) - { - Ensure.ArgumentNotNullOrWhiteSpace(solutionDir, nameof(solutionDir)); - - var projectExtensions = new[] { "*.csproj", "*.vbproj", "*.fsproj" }; - return projectExtensions - .SelectMany(ext => Directory.GetFiles(solutionDir, ext, SearchOption.AllDirectories)) - .Where(file => ShouldIncludeProject(file, excludePatterns)) - .ToArray(); - } - - /// - /// Determines if a project file should be included based on exclude patterns. - /// - /// The project file path. - /// Patterns to exclude. - /// true if the project should be included; otherwise, false. - internal bool ShouldIncludeProject(string projectFilePath, string[]? excludePatterns) - { - Ensure.ArgumentNotNullOrWhiteSpace(projectFilePath, nameof(projectFilePath)); - - if (excludePatterns is null || excludePatterns.Length == 0) - { - return true; - } - - var fileName = Path.GetFileNameWithoutExtension(projectFilePath); - return !excludePatterns.Any(pattern => - fileName.Contains(pattern.Replace("*", ""), StringComparison.OrdinalIgnoreCase)); - } - - /// - /// Evaluates if a project should be documented based on its properties. - /// - /// The MSBuild project to evaluate. - /// true if the project should be documented; otherwise, false. - internal bool ShouldDocumentProject(Project project) - { - Ensure.ArgumentNotNull(project, nameof(project)); - - foreach (var prop in _propertiesToEvaluate) - { - var propValue = project.GetPropertyValue(prop.Key); - if (string.Equals(propValue, "true", StringComparison.OrdinalIgnoreCase) != prop.Value) - { - return false; - } - } - - return true; - } - - /// - /// Creates a task item with metadata for a documented project. - /// - /// The MSBuild project. - /// The project file path. - /// A task item with appropriate metadata. - internal ITaskItem CreateProjectTaskItem(Project project, string projectFilePath) - { - Ensure.ArgumentNotNull(project, nameof(project)); - Ensure.ArgumentNotNullOrWhiteSpace(projectFilePath, nameof(projectFilePath)); - - var projectName = Path.GetFileNameWithoutExtension(projectFilePath); - var item = new TaskItem(projectFilePath); - - // Set metadata from the evaluated project - var assemblyName = project.GetPropertyValue("AssemblyName"); - if (string.IsNullOrEmpty(assemblyName)) - { - assemblyName = projectName; - } - - var targetFramework = GetProjectTargetFramework(project); - - item.SetMetadata("AssemblyName", assemblyName); - item.SetMetadata("OutputPath", $"bin\\{Configuration}"); - item.SetMetadata("TargetFramework", targetFramework); - item.SetMetadata("TargetPath", $"bin\\{Configuration}\\{targetFramework}\\{assemblyName}.dll"); - - return item; - } - - /// - /// Gets the target framework for a project, handling both single and multi-targeted projects. - /// - /// The MSBuild project. - /// The target framework string. - internal string GetProjectTargetFramework(Project project) - { - Ensure.ArgumentNotNull(project, nameof(project)); - - var targetFramework = project.GetPropertyValue("TargetFramework"); - if (!string.IsNullOrEmpty(targetFramework)) - { - return targetFramework; - } - - // For multi-targeted projects, use TargetFrameworks and pick the first one - var targetFrameworks = project.GetPropertyValue("TargetFrameworks"); - if (!string.IsNullOrEmpty(targetFrameworks)) - { - return targetFrameworks.Split(';')[0].Trim(); - } - - // Use default - return TargetFramework; - } - - #endregion - - } - -} \ No newline at end of file diff --git a/src/CloudNimble.DotNetDocs.Sdk/CloudNimble.DotNetDocs.Sdk.csproj b/src/CloudNimble.DotNetDocs.Sdk/CloudNimble.DotNetDocs.Sdk.csproj index 2a6f12c..0c2b8ab 100644 --- a/src/CloudNimble.DotNetDocs.Sdk/CloudNimble.DotNetDocs.Sdk.csproj +++ b/src/CloudNimble.DotNetDocs.Sdk/CloudNimble.DotNetDocs.Sdk.csproj @@ -1,8 +1,8 @@ - + - netstandard2.0 + net8.0;net472 false The MSBuild SDK for documentation projects (.docsproj) that provides a clean way to include documentation in .NET solutions. @@ -10,6 +10,8 @@ true MSBuildSdk true + true + false $(NoWarn);NU5128;CS2008;NU1701;NU5100 @@ -19,65 +21,55 @@ true + $(TargetsForTfmSpecificContentInPackage);AddPerTFMDocsTasksToPackage - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + <_TargetsForReferenceOutputs>ReferenceCopyLocalPathsOutputGroup;BuiltProjectOutputGroup + + + + + + - + + - - - - @@ -102,19 +94,4 @@ - - - - - $(PkgMicrosoft_Build_NoTargets)\Sdk - - - - - - - - - - \ No newline at end of file diff --git a/src/CloudNimble.DotNetDocs.Sdk.Tasks/GenerateDocumentationTask.cs b/src/CloudNimble.DotNetDocs.Sdk/GenerateDocumentationTask.cs similarity index 97% rename from src/CloudNimble.DotNetDocs.Sdk.Tasks/GenerateDocumentationTask.cs rename to src/CloudNimble.DotNetDocs.Sdk/GenerateDocumentationTask.cs index df40733..2e89ab5 100644 --- a/src/CloudNimble.DotNetDocs.Sdk.Tasks/GenerateDocumentationTask.cs +++ b/src/CloudNimble.DotNetDocs.Sdk/GenerateDocumentationTask.cs @@ -295,16 +295,6 @@ public override bool Execute() generatedFiles.AddRange(yamlFiles); } - // Log statistics - Log.LogMessage(MessageImportance.High, "📊 Documentation Statistics:"); - Log.LogMessage(MessageImportance.High, $" 📄 Documentation type: {DocumentationType}"); - Log.LogMessage(MessageImportance.High, $" 📦 Assemblies processed: {assemblyPairs.Count}"); - - if (generatedFiles.Count > 0) - { - Log.LogMessage(MessageImportance.High, $" 📝 Files generated: {generatedFiles.Distinct().Count()}"); - } - // Return generated files as output GeneratedFiles = [.. generatedFiles.Distinct().Select(f => new TaskItem(f))]; @@ -497,7 +487,7 @@ internal NavigationConfig ParseNavigationConfig(XElement navigationElement) /// /// The group XML element. /// A GroupConfig instance, or null if parsing fails. - internal GroupConfig? ParseGroupConfig(XElement groupElement) + public GroupConfig? ParseGroupConfig(XElement groupElement) { var groupName = groupElement.Attribute("Name")?.Value; if (string.IsNullOrWhiteSpace(groupName)) @@ -551,7 +541,7 @@ internal NavigationConfig ParseNavigationConfig(XElement navigationElement) /// /// The integrations XML element. /// An IntegrationsConfig instance. - internal IntegrationsConfig ParseIntegrationsConfig(XElement integrationsElement) + public IntegrationsConfig ParseIntegrationsConfig(XElement integrationsElement) { var config = new IntegrationsConfig(); @@ -706,7 +696,7 @@ internal IntegrationsConfig ParseIntegrationsConfig(XElement integrationsElement /// /// The styling XML element. /// A StylingConfig instance. - internal StylingConfig ParseStylingConfig(XElement stylingElement) + public StylingConfig ParseStylingConfig(XElement stylingElement) { var config = new StylingConfig(); @@ -732,7 +722,7 @@ internal StylingConfig ParseStylingConfig(XElement stylingElement) /// /// The appearance XML element. /// An AppearanceConfig instance. - internal AppearanceConfig ParseAppearanceConfig(XElement appearanceElement) + public AppearanceConfig ParseAppearanceConfig(XElement appearanceElement) { var config = new AppearanceConfig(); diff --git a/src/CloudNimble.DotNetDocs.Sdk/Sdk/Sdk.props b/src/CloudNimble.DotNetDocs.Sdk/Sdk/Sdk.props index eef732a..f5b0e49 100644 --- a/src/CloudNimble.DotNetDocs.Sdk/Sdk/Sdk.props +++ b/src/CloudNimble.DotNetDocs.Sdk/Sdk/Sdk.props @@ -6,7 +6,6 @@ Enables documentation files to be included in Visual Studio solutions without compilation overhead or bin/obj folder creation. ============================================================================ --> - true @@ -16,9 +15,6 @@ {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - true - net8.0 @@ -73,23 +69,7 @@ $(BaseIntermediateOutputPath) - - - - - - - - - <_NoTargetsFallbackPath>$(UserProfile)\.nuget\packages\microsoft.build.notargets\3.7.0\Sdk\Sdk.props - - <_NoTargetsFallbackPath Condition="!Exists('$(_NoTargetsFallbackPath)')">$(NuGetPackageRoot)microsoft.build.notargets\3.7.0\Sdk\Sdk.props - - - - + diff --git a/src/CloudNimble.DotNetDocs.Sdk/Sdk/Sdk.targets b/src/CloudNimble.DotNetDocs.Sdk/Sdk/Sdk.targets index f39be88..8b40b65 100644 --- a/src/CloudNimble.DotNetDocs.Sdk/Sdk/Sdk.targets +++ b/src/CloudNimble.DotNetDocs.Sdk/Sdk/Sdk.targets @@ -6,23 +6,7 @@ Includes validation, generation, and integration targets. ============================================================================ --> - - - - - - - - - <_NoTargetsTargetsFallbackPath>$(UserProfile)\.nuget\packages\microsoft.build.notargets\3.7.0\Sdk\Sdk.targets - - <_NoTargetsTargetsFallbackPath Condition="!Exists('$(_NoTargetsTargetsFallbackPath)')">$(NuGetPackageRoot)microsoft.build.notargets\3.7.0\Sdk\Sdk.targets - - - - + @@ -31,88 +15,91 @@ <_DotNetDocsTaskFramework Condition="'$(MSBuildRuntimeType)' == 'Full'">net472 <_DotNetDocsTaskFramework Condition="'$(_DotNetDocsTaskFramework)' == ''">net8.0 - - <_DotNetDocsTasksFolder>$(MSBuildThisFileDirectory)..\tasks\$(_DotNetDocsTaskFramework) - <_DotNetDocsTasksAssembly>$(_DotNetDocsTasksFolder)\CloudNimble.DotNetDocs.Sdk.Tasks.dll + + <_DotNetDocsTasksFolder Condition="'$(_DotNetDocsTasksFolder)' == ''">$(MSBuildThisFileDirectory)..\tasks\ + <_DotNetDocsTasksAssembly >$(_DotNetDocsTasksFolder)$(_DotNetDocsTaskFramework)\CloudNimble.DotNetDocs.Sdk.dll + + AssignDocumentationProjectReferences;$(PrepareProjectReferencesDependsOn) - - - - - + AssemblyFile="$(_DotNetDocsTasksAssembly)"/> + + + - - + + <_AllProjectsInRoot Include="$(IncludePatterns)" Exclude="@(ExcludePatterns)"/> + - - - - - - - - - - - - - - - - - + + + + + + + + + + + - + + + + - <_ProjectNames Include="@(DocumentedProjects->'%(Filename)')" /> + - - + + DependsOnTargets="DiscoverDocumentedProjects;ResolveProjectReferences"> - - + + - - - - - $(MSBuildProjectDirectory) $(NamespaceMode) - - - - - - + + + + - - - @@ -189,12 +177,10 @@ - + - - @@ -205,10 +191,8 @@ - - diff --git a/src/CloudNimble.DotNetDocs.Sdk/readme.md b/src/CloudNimble.DotNetDocs.Sdk/readme.md index 737ea74..15834fb 100644 --- a/src/CloudNimble.DotNetDocs.Sdk/readme.md +++ b/src/CloudNimble.DotNetDocs.Sdk/readme.md @@ -93,8 +93,6 @@ The SDK automatically detects your documentation type based on configuration fil true - true - true ``` @@ -130,8 +128,6 @@ This is particularly useful when you want to: | `GenerateMintlifyDocs` | Generate Mintlify documentation (requires EasyAF.Tools) | | `LintMarkdown` | Lint markdown files for issues | | `PreviewDocumentation` | Start local preview server | -| `ValidateLinks` | Check for broken links | -| `GeneratePdf` | Generate PDF output | | `DeployDocumentation` | Deploy to hosting platform | ### DotNetDocs Integration diff --git a/src/CloudNimble.DotNetDocs.Sdk/work-plan.md b/src/CloudNimble.DotNetDocs.Sdk/work-plan.md new file mode 100644 index 0000000..4eacccb --- /dev/null +++ b/src/CloudNimble.DotNetDocs.Sdk/work-plan.md @@ -0,0 +1,14 @@ +* Improve current SDK implementation + * improve discovery Task/logic + * don't do eval in DiscoverDocumentedProjectsTask x + * instead use Target calls x + * ensure that referenced projects are built before documentation generation x + * incrementality + * add a placeholder for multi-tfm handling + * improve sdk packaging x + * use nuget's per-tfm capabilities to do the current Task packaging x + * remove need for separate project x + * ensure deps are bundled per-TFM as well for correct loading x + * remove use of pinned-per-tfm extensions deps - newer versions are back-compatible x + * improve local use of custom SDK + * add explicit Imports to local samples for Sdk.props and Sdk.targets to remove need to build entire package and manage nuget package versions diff --git a/src/CloudNimble.DotNetDocs.Tests.Sdk.Tasks/CloudNimble.DotNetDocs.Tests.Sdk.Tasks.csproj b/src/CloudNimble.DotNetDocs.Tests.Sdk.Tasks/CloudNimble.DotNetDocs.Tests.Sdk.Tasks.csproj index 3aef87b..0a68e46 100644 --- a/src/CloudNimble.DotNetDocs.Tests.Sdk.Tasks/CloudNimble.DotNetDocs.Tests.Sdk.Tasks.csproj +++ b/src/CloudNimble.DotNetDocs.Tests.Sdk.Tasks/CloudNimble.DotNetDocs.Tests.Sdk.Tasks.csproj @@ -14,8 +14,9 @@ - + + diff --git a/src/CloudNimble.DotNetDocs.Tests.Sdk.Tasks/DiscoverDocumentedProjectsTaskTests.cs b/src/CloudNimble.DotNetDocs.Tests.Sdk.Tasks/DiscoverDocumentedProjectsTaskTests.cs deleted file mode 100644 index de8a1f5..0000000 --- a/src/CloudNimble.DotNetDocs.Tests.Sdk.Tasks/DiscoverDocumentedProjectsTaskTests.cs +++ /dev/null @@ -1,302 +0,0 @@ -using System; -using System.IO; -using CloudNimble.DotNetDocs.Sdk.Tasks; -using CloudNimble.DotNetDocs.Tests.Shared; -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace CloudNimble.DotNetDocs.Tests.Sdk.Tasks -{ - - /// - /// Tests for the DiscoverDocumentedProjectsTask class, focusing on project discovery and filtering logic. - /// - [TestClass] - public class DiscoverDocumentedProjectsTaskTests : DotNetDocsTestBase - { - - #region Fields - - private DiscoverDocumentedProjectsTask _task = null!; - private string _tempDirectory = null!; - - #endregion - - #region Test Lifecycle - - [TestInitialize] - public void TestInitialize() - { - TestSetup(); - _task = new DiscoverDocumentedProjectsTask(); - - // Set up a minimal build engine to avoid logging errors - var buildEngine = new TestBuildEngine(); - _task.BuildEngine = buildEngine; - - // Create a temporary directory for test files - _tempDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - Directory.CreateDirectory(_tempDirectory); - } - - [TestCleanup] - public void TestCleanup() - { - // Clean up temporary files - if (Directory.Exists(_tempDirectory)) - { - Directory.Delete(_tempDirectory, true); - } - - TestTearDown(); - } - - #endregion - - #region Project Discovery Tests - - /// - /// Tests that DiscoverProjectFiles finds all project types. - /// - [TestMethod] - public void DiscoverProjectFiles_WithValidDirectory_FindsAllProjectTypes() - { - // Create test project files - File.WriteAllText(Path.Combine(_tempDirectory, "Test1.csproj"), ""); - File.WriteAllText(Path.Combine(_tempDirectory, "Test2.vbproj"), ""); - File.WriteAllText(Path.Combine(_tempDirectory, "Test3.fsproj"), ""); - File.WriteAllText(Path.Combine(_tempDirectory, "NotProject.txt"), "text file"); - - var result = _task.DiscoverProjectFiles(_tempDirectory, null); - - result.Should().HaveCount(3); - result.Should().Contain(p => p.EndsWith("Test1.csproj")); - result.Should().Contain(p => p.EndsWith("Test2.vbproj")); - result.Should().Contain(p => p.EndsWith("Test3.fsproj")); - } - - /// - /// Tests that DiscoverProjectFiles excludes projects based on patterns. - /// - [TestMethod] - public void DiscoverProjectFiles_WithExcludePatterns_ExcludesMatchingProjects() - { - // Create test project files - File.WriteAllText(Path.Combine(_tempDirectory, "MyProject.csproj"), ""); - File.WriteAllText(Path.Combine(_tempDirectory, "MyProject.Tests.csproj"), ""); - File.WriteAllText(Path.Combine(_tempDirectory, "MyProject.IntegrationTests.csproj"), ""); - - var excludePatterns = new[] { "Tests", "IntegrationTests" }; - var result = _task.DiscoverProjectFiles(_tempDirectory, excludePatterns); - - result.Should().HaveCount(1); - result.Should().Contain(p => p.EndsWith("MyProject.csproj")); - } - - /// - /// Tests that DiscoverProjectFiles finds projects in subdirectories. - /// - [TestMethod] - public void DiscoverProjectFiles_WithSubdirectories_FindsProjectsRecursively() - { - // Create subdirectory and project - var subDir = Path.Combine(_tempDirectory, "SubFolder"); - Directory.CreateDirectory(subDir); - File.WriteAllText(Path.Combine(subDir, "SubProject.csproj"), ""); - File.WriteAllText(Path.Combine(_tempDirectory, "RootProject.csproj"), ""); - - var result = _task.DiscoverProjectFiles(_tempDirectory, null); - - result.Should().HaveCount(2); - result.Should().Contain(p => p.EndsWith("RootProject.csproj")); - result.Should().Contain(p => p.EndsWith("SubProject.csproj")); - } - - #endregion - - #region Project Filtering Tests - - /// - /// Tests that ShouldIncludeProject returns true when no exclude patterns are provided. - /// - [TestMethod] - public void ShouldIncludeProject_WithNoExcludePatterns_ReturnsTrue() - { - var projectPath = Path.Combine(_tempDirectory, "TestProject.csproj"); - - var result = _task.ShouldIncludeProject(projectPath, null); - - result.Should().BeTrue(); - } - - /// - /// Tests that ShouldIncludeProject returns true when project doesn't match exclude patterns. - /// - [TestMethod] - public void ShouldIncludeProject_WithNonMatchingPatterns_ReturnsTrue() - { - var projectPath = Path.Combine(_tempDirectory, "MyProject.csproj"); - var excludePatterns = new[] { "Tests", "Samples" }; - - var result = _task.ShouldIncludeProject(projectPath, excludePatterns); - - result.Should().BeTrue(); - } - - /// - /// Tests that ShouldIncludeProject returns false when project matches exclude patterns. - /// - [TestMethod] - public void ShouldIncludeProject_WithMatchingPattern_ReturnsFalse() - { - var projectPath = Path.Combine(_tempDirectory, "MyProject.Tests.csproj"); - var excludePatterns = new[] { "Tests", "Samples" }; - - var result = _task.ShouldIncludeProject(projectPath, excludePatterns); - - result.Should().BeFalse(); - } - - /// - /// Tests that ShouldIncludeProject matching is case insensitive. - /// - [TestMethod] - public void ShouldIncludeProject_WithCaseInsensitiveMatch_ReturnsFalse() - { - var projectPath = Path.Combine(_tempDirectory, "MyProject.TESTS.csproj"); - var excludePatterns = new[] { "tests" }; - - var result = _task.ShouldIncludeProject(projectPath, excludePatterns); - - result.Should().BeFalse(); - } - - /// - /// Tests that ShouldIncludeProject handles wildcard patterns correctly. - /// - [TestMethod] - public void ShouldIncludeProject_WithWildcardPattern_HandlesCorrectly() - { - var projectPath = Path.Combine(_tempDirectory, "MyProject.Tests.csproj"); - var excludePatterns = new[] { "*Tests*" }; - - var result = _task.ShouldIncludeProject(projectPath, excludePatterns); - - result.Should().BeFalse(); - } - - #endregion - - #region Properties Tests - - /// - /// Tests that _propertiesToEvaluate contains the expected properties and values. - /// - [TestMethod] - public void PropertiesToEvaluate_ContainsExpectedProperties() - { - _task._propertiesToEvaluate.Should().ContainKey("IsTestProject") - .WhoseValue.Should().BeFalse(); - _task._propertiesToEvaluate.Should().ContainKey("IsPackable") - .WhoseValue.Should().BeTrue(); - _task._propertiesToEvaluate.Should().ContainKey("ExcludeFromDocumentation") - .WhoseValue.Should().BeFalse(); - } - - /// - /// Tests that properties can be modified for testing scenarios. - /// - [TestMethod] - public void PropertiesToEvaluate_CanBeModified() - { - _task._propertiesToEvaluate["IsTestProject"] = true; - _task._propertiesToEvaluate.Should().ContainKey("IsTestProject") - .WhoseValue.Should().BeTrue(); - } - - #endregion - - #region Task Property Tests - - /// - /// Tests that task properties have correct default values. - /// - [TestMethod] - public void TaskProperties_HaveCorrectDefaults() - { - _task.Configuration.Should().Be("Release"); - _task.TargetFramework.Should().Be("net8.0"); - _task.DocumentedProjects.Should().BeEmpty(); - } - - /// - /// Tests that task properties can be set. - /// - [TestMethod] - public void TaskProperties_CanBeSet() - { - _task.SolutionDir = "C:\\TestSolution"; - _task.Configuration = "Debug"; - _task.TargetFramework = "net9.0"; - _task.ExcludePatterns = new[] { "Tests" }; - - _task.SolutionDir.Should().Be("C:\\TestSolution"); - _task.Configuration.Should().Be("Debug"); - _task.TargetFramework.Should().Be("net9.0"); - _task.ExcludePatterns.Should().ContainSingle("Tests"); - } - - #endregion - - #region Argument Validation Tests - - /// - /// Tests that DiscoverProjectFiles throws ArgumentException for null or whitespace solution directory. - /// - [TestMethod] - public void DiscoverProjectFiles_WithNullSolutionDir_ThrowsArgumentException() - { - var action = () => _task.DiscoverProjectFiles(null!, null); - - action.Should().Throw(); - } - - /// - /// Tests that DiscoverProjectFiles throws ArgumentException for whitespace solution directory. - /// - [TestMethod] - public void DiscoverProjectFiles_WithWhitespaceSolutionDir_ThrowsArgumentException() - { - var action = () => _task.DiscoverProjectFiles(" ", null); - - action.Should().Throw(); - } - - /// - /// Tests that ShouldIncludeProject throws ArgumentException for null or whitespace project file path. - /// - [TestMethod] - public void ShouldIncludeProject_WithNullProjectPath_ThrowsArgumentException() - { - var action = () => _task.ShouldIncludeProject(null!, null); - - action.Should().Throw(); - } - - /// - /// Tests that ShouldIncludeProject throws ArgumentException for whitespace project file path. - /// - [TestMethod] - public void ShouldIncludeProject_WithWhitespaceProjectPath_ThrowsArgumentException() - { - var action = () => _task.ShouldIncludeProject(" ", null); - - action.Should().Throw(); - } - - #endregion - - - } - -} \ No newline at end of file diff --git a/test/MultiAssembly.ByAssembly.docsproj b/test/MultiAssembly.ByAssembly.docsproj index 260f745..ecb48f6 100644 --- a/test/MultiAssembly.ByAssembly.docsproj +++ b/test/MultiAssembly.ByAssembly.docsproj @@ -1,11 +1,15 @@ - + + $(MSBuildProjectDirectory)\byassembly-docs\ + true Mintlify Folder ByAssembly + *.docsproj;**.docsproj + ../src/**/*.csproj @@ -34,4 +38,10 @@ + + <_DotNetDocsTasksFolder>$(MSBuildThisFileDirectory)..\src\CloudNimble.DotNetDocs.Sdk\bin\Debug\ + + + + \ No newline at end of file