diff --git a/docs/source-code-inclusion.md b/docs/source-code-inclusion.md index 65630a6..a14cecb 100644 --- a/docs/source-code-inclusion.md +++ b/docs/source-code-inclusion.md @@ -44,6 +44,7 @@ Configuration keys are case-insensitive. Nested command-line keys use `:`, for e | `SourceFolder` | Repository `src/Light.GuardClauses` | Directory containing the source files | | `TargetFile` | Root `Light.GuardClauses.SingleFile.cs` | Generated output path | | `TargetFramework` | `NetStandard2_0` | Selects `NetStandard2_0` or `Net10_0` | +| `ValidateGeneratedFileBuild` | `true` | Builds the generated file after export; set to `false` to skip validation | | `ChangePublicTypesToInternalTypes` | `true` | Makes exported public types internal | | `BaseNamespace` | `Light.GuardClauses` | Rewrites the base namespace | | `RemoveContractAnnotations` | `false` | Removes JetBrains contract annotations from members | @@ -119,6 +120,6 @@ The exporter fails loudly if a `Check..cs` assertion file has no correspon ## Validation and failures -After writing the target file, the tool builds it through [`Light.GuardClauses.SourceValidation`](../tools/source-export/Light.GuardClauses.SourceValidation/) using `netstandard2.0` or `net10.0` to match the selected source target. +After writing the target file, the tool builds it through [`Light.GuardClauses.SourceValidation`](../tools/source-export/Light.GuardClauses.SourceValidation/) using `netstandard2.0` or `net10.0` to match the selected source target. Set `ValidateGeneratedFileBuild` to `false` to skip this validation when the caller will validate the output separately. If generation throws, the tool prints the exception and returns a non-zero exit code. If validation fails, it prints the captured build output and returns the build's non-zero exit code. In either case, a file already generated is left in place for diagnosis. Do not publish or commit custom output unless the command and matching validation complete successfully. diff --git a/tests/Light.GuardClauses.SourceCodeTransformation.Tests/GeneratedFileBuildValidatorTests.cs b/tests/Light.GuardClauses.SourceCodeTransformation.Tests/GeneratedFileBuildValidatorTests.cs index 7ba4378..98e5254 100644 --- a/tests/Light.GuardClauses.SourceCodeTransformation.Tests/GeneratedFileBuildValidatorTests.cs +++ b/tests/Light.GuardClauses.SourceCodeTransformation.Tests/GeneratedFileBuildValidatorTests.cs @@ -19,15 +19,13 @@ public static void TryFindSourceValidationProjectFindsProjectFromRepositoryRoot( ); GeneratedFileBuildValidator.TryFindSourceValidationProject([TestEnvironment.RepositoryRoot.FullName]) - .Should().Be(expectedProjectPath); + .Should().Be(expectedProjectPath); } [Fact] - public static void TryFindSourceValidationProjectFindsProjectFromTestOutputDirectory() - { + public static void TryFindSourceValidationProjectFindsProjectFromTestOutputDirectory() => GeneratedFileBuildValidator.TryFindSourceValidationProject([AppContext.BaseDirectory]) - .Should().NotBeNull(); - } + .Should().NotBeNull(); [Fact] public static void SourceFileMergeOptionsUseRepositoryLayoutDefaults() @@ -38,6 +36,7 @@ public static void SourceFileMergeOptionsUseRepositoryLayoutDefaults() options.TargetFile.Should().Be( Path.Combine(TestEnvironment.RepositoryRoot.FullName, "Light.GuardClauses.SingleFile.cs") ); + options.ValidateGeneratedFileBuild.Should().BeTrue(); } [Fact] @@ -90,4 +89,45 @@ public static void ProgramRunsNonWhitelistNetStandardTransformationAndValidates( File.Exists(targetFile).Should().BeTrue(); } + + [Fact] + public static void ProgramCanSkipGeneratedFileBuildValidation() + { + using var temporaryDirectory = new TemporaryDirectory(); + var sourceFolder = Path.Combine(temporaryDirectory.DirectoryPath, "Source"); + Directory.CreateDirectory(sourceFolder); + File.WriteAllText( + Path.Combine(sourceFolder, "Check.cs"), + "namespace Light.GuardClauses; public static partial class Check { }" + ); + File.WriteAllText( + Path.Combine(sourceFolder, "Check.Invalid.cs"), + """ + namespace Light.GuardClauses; + public static partial class Check + { + public static UndefinedType Invalid() => null; + } + """ + ); + File.WriteAllText( + Path.Combine(sourceFolder, "Throw.cs"), + "namespace Light.GuardClauses.ExceptionFactory; public static partial class Throw { }" + ); + var targetFile = Path.Combine(temporaryDirectory.DirectoryPath, "Generated.cs"); + + Program.Main( + [ + $"SourceFolder={sourceFolder}", + $"TargetFile={targetFile}", + "IncludeVersionComment=false", + "IncludeJetBrainsAnnotations=false", + "IncludeJetBrainsAnnotationsUsing=false", + "TargetFramework=Net10_0", + "ValidateGeneratedFileBuild=false", + ] + ).Should().Be(0); + + File.ReadAllText(targetFile).Should().Contain("UndefinedType"); + } } diff --git a/tools/source-export/Light.GuardClauses.SourceCodeTransformation/Program.cs b/tools/source-export/Light.GuardClauses.SourceCodeTransformation/Program.cs index 1d887b7..eb352ae 100644 --- a/tools/source-export/Light.GuardClauses.SourceCodeTransformation/Program.cs +++ b/tools/source-export/Light.GuardClauses.SourceCodeTransformation/Program.cs @@ -20,11 +20,14 @@ public static int Main(string[] args) { Console.WriteLine("Merging source files..."); SourceFileMerger.CreateSingleSourceFile(options); - var buildValidationExitCode = - GeneratedFileBuildValidator.Validate(options.TargetFramework, options.TargetFile); - if (buildValidationExitCode != 0) + if (options.ValidateGeneratedFileBuild) { - return buildValidationExitCode; + var buildValidationExitCode = + GeneratedFileBuildValidator.Validate(options.TargetFramework, options.TargetFile); + if (buildValidationExitCode != 0) + { + return buildValidationExitCode; + } } Console.WriteLine("Source file export completed successfully."); diff --git a/tools/source-export/Light.GuardClauses.SourceCodeTransformation/SourceFileMergeOptions.cs b/tools/source-export/Light.GuardClauses.SourceCodeTransformation/SourceFileMergeOptions.cs index 2bea4b4..f27a2e0 100644 --- a/tools/source-export/Light.GuardClauses.SourceCodeTransformation/SourceFileMergeOptions.cs +++ b/tools/source-export/Light.GuardClauses.SourceCodeTransformation/SourceFileMergeOptions.cs @@ -30,6 +30,8 @@ public SourceFileMergeOptions() public SourceTargetFramework TargetFramework { get; init; } = SourceTargetFramework.NetStandard2_0; + public bool ValidateGeneratedFileBuild { get; init; } = true; + public AssertionWhitelist AssertionWhitelist { get; init; } = new (); public bool ChangePublicTypesToInternalTypes { get; init; } = true; diff --git a/tools/source-export/Light.GuardClauses.SourceCodeTransformation/settings.json b/tools/source-export/Light.GuardClauses.SourceCodeTransformation/settings.json index 8e0fc27..412dd8d 100644 --- a/tools/source-export/Light.GuardClauses.SourceCodeTransformation/settings.json +++ b/tools/source-export/Light.GuardClauses.SourceCodeTransformation/settings.json @@ -2,6 +2,7 @@ "SourceFolder": "", "TargetFile": "", "TargetFramework": "NetStandard2_0", + "ValidateGeneratedFileBuild": true, "ChangePublicTypesToInternalTypes": true, "BaseNamespace": "Light.GuardClauses", "RemoveContractAnnotations": false,