Skip to content

Commit 5643028

Browse files
thomhurstclaude
andcommitted
feat: standardize generated files to use .Generated.cs suffix
- Update all generators (Options, Services, Enums, SubDomain) to use .Generated.cs suffix - Update cleanup logic to only delete *.Generated.cs files - Add transition support: cleanup also removes legacy auto-generated files by checking for <auto-generated> header - Hand-written files in Options/Services/Extensions/Enums directories are now preserved automatically This ensures hand-written code like AzureExtensions.cs, DockerExtensions.cs, etc. won't be accidentally deleted when the generator runs. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent deb3693 commit 5643028

6 files changed

Lines changed: 55 additions & 29 deletions

File tree

tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Generators/CodeGeneratorOrchestrator.cs

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -356,8 +356,8 @@ private static async Task WriteAssemblyInfoAsync(
356356

357357
/// <summary>
358358
/// Cleans up old generated files before regenerating.
359-
/// Deletes all .cs files in Options, Services, Extensions directories since they'll be regenerated.
360-
/// Preserves Enums directory (only deletes .Generated.cs there) to keep manually-defined enums.
359+
/// Deletes *.Generated.cs files and legacy auto-generated files (transition support).
360+
/// Hand-written files (without auto-generated header) are preserved.
361361
/// </summary>
362362
private void CleanupGeneratedFiles(string outputDirectory, string toolOutputDirectory, string namespacePrefix)
363363
{
@@ -367,53 +367,79 @@ private void CleanupGeneratedFiles(string outputDirectory, string toolOutputDire
367367
return;
368368
}
369369

370-
// Directories where ALL .cs files should be deleted (completely regenerated)
371-
var fullyRegeneratedDirs = new[] { "Options", "Services", "Extensions" };
370+
var generatedDirs = new[] { "Options", "Services", "Extensions", "Enums" };
372371

373-
foreach (var subDir in fullyRegeneratedDirs)
372+
foreach (var subDir in generatedDirs)
374373
{
375374
var subDirPath = Path.Combine(toolPath, subDir);
376375
if (!Directory.Exists(subDirPath))
377376
{
378377
continue;
379378
}
380379

381-
// Delete ALL .cs files in this directory (they will be regenerated)
380+
// Delete all *.Generated.cs files (new naming convention)
381+
var generatedFiles = Directory.GetFiles(subDirPath, "*.Generated.cs", SearchOption.TopDirectoryOnly);
382+
foreach (var file in generatedFiles)
383+
{
384+
DeleteFileIfExists(file);
385+
}
386+
387+
// Also clean up legacy auto-generated files (transition support)
388+
// These are files without .Generated.cs suffix but with <auto-generated> header
382389
var allCsFiles = Directory.GetFiles(subDirPath, "*.cs", SearchOption.TopDirectoryOnly);
383390
foreach (var file in allCsFiles)
384391
{
385-
try
392+
if (file.EndsWith(".Generated.cs", StringComparison.OrdinalIgnoreCase))
386393
{
387-
File.Delete(file);
388-
_logger.LogDebug("Deleted file for regeneration: {File}", file);
394+
continue; // Already handled above
389395
}
390-
catch (Exception ex)
396+
397+
if (IsAutoGeneratedFile(file))
391398
{
392-
_logger.LogWarning(ex, "Failed to delete file: {File}", file);
399+
DeleteFileIfExists(file);
393400
}
394401
}
395402
}
396403

397-
// For Enums directory, only delete .Generated.cs files (preserve manually-defined enums)
398-
var enumsPath = Path.Combine(toolPath, "Enums");
399-
if (Directory.Exists(enumsPath))
404+
_logger.LogInformation("Cleaned up old files in {Path}", toolPath);
405+
}
406+
407+
/// <summary>
408+
/// Checks if a file contains the auto-generated header marker.
409+
/// </summary>
410+
private static bool IsAutoGeneratedFile(string filePath)
411+
{
412+
try
400413
{
401-
var generatedEnumFiles = Directory.GetFiles(enumsPath, "*.Generated.cs", SearchOption.TopDirectoryOnly);
402-
foreach (var file in generatedEnumFiles)
414+
// Read first few lines to check for auto-generated marker
415+
using var reader = new StreamReader(filePath);
416+
for (var i = 0; i < 5 && !reader.EndOfStream; i++)
403417
{
404-
try
418+
var line = reader.ReadLine();
419+
if (line != null && line.Contains("<auto-generated>", StringComparison.OrdinalIgnoreCase))
405420
{
406-
File.Delete(file);
407-
_logger.LogDebug("Deleted old generated enum file: {File}", file);
408-
}
409-
catch (Exception ex)
410-
{
411-
_logger.LogWarning(ex, "Failed to delete old generated enum file: {File}", file);
421+
return true;
412422
}
413423
}
424+
return false;
414425
}
426+
catch
427+
{
428+
return false;
429+
}
430+
}
415431

416-
_logger.LogInformation("Cleaned up old files in {Path}", toolPath);
432+
private void DeleteFileIfExists(string file)
433+
{
434+
try
435+
{
436+
File.Delete(file);
437+
_logger.LogDebug("Deleted old generated file: {File}", file);
438+
}
439+
catch (Exception ex)
440+
{
441+
_logger.LogWarning(ex, "Failed to delete file: {File}", file);
442+
}
417443
}
418444
}
419445

tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Generators/EnumGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public Task<IReadOnlyList<GeneratedFile>> GenerateAsync(CliToolDefinition tool,
1515
foreach (var enumDef in tool.AllEnums)
1616
{
1717
var content = GenerateEnum(enumDef, tool);
18-
var fileName = $"{enumDef.EnumName}.cs";
18+
var fileName = $"{enumDef.EnumName}.Generated.cs";
1919
var relativePath = Path.Combine(tool.OutputDirectory, "Enums", fileName);
2020

2121
files.Add(new GeneratedFile

tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Generators/OptionsClassGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public Task<IReadOnlyList<GeneratedFile>> GenerateAsync(CliToolDefinition tool,
1515
foreach (var command in tool.Commands)
1616
{
1717
var content = GenerateOptionsClass(command, tool);
18-
var fileName = $"{command.ClassName}.cs";
18+
var fileName = $"{command.ClassName}.Generated.cs";
1919
var relativePath = Path.Combine(tool.OutputDirectory, "Options", fileName);
2020

2121
files.Add(new GeneratedFile

tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Generators/ServiceImplementationGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public Task<IReadOnlyList<GeneratedFile>> GenerateAsync(CliToolDefinition tool,
1515

1616
// Generate the main service implementation
1717
var mainContent = GenerateMainServiceClass(tool);
18-
var mainFileName = $"{tool.NamespacePrefix}.cs";
18+
var mainFileName = $"{tool.NamespacePrefix}.Generated.cs";
1919
var mainRelativePath = Path.Combine(tool.OutputDirectory, "Services", mainFileName);
2020

2121
files.Add(new GeneratedFile

tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Generators/ServiceInterfaceGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class ServiceInterfaceGenerator : ICodeGenerator
1111
public Task<IReadOnlyList<GeneratedFile>> GenerateAsync(CliToolDefinition tool, CancellationToken cancellationToken = default)
1212
{
1313
var content = GenerateInterface(tool);
14-
var fileName = $"I{tool.NamespacePrefix}.cs";
14+
var fileName = $"I{tool.NamespacePrefix}.Generated.cs";
1515
var relativePath = Path.Combine(tool.OutputDirectory, "Services", fileName);
1616

1717
var files = new List<GeneratedFile>

tools/ModularPipelines.OptionsGenerator/src/ModularPipelines.OptionsGenerator/Generators/SubDomainClassGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ private static void GenerateFilesFromTree(
9494
node.Depth == 0 ? parentCommand : null,
9595
collidingCommands.Values.ToHashSet());
9696

97-
var fileName = $"{node.ClassName}.cs";
97+
var fileName = $"{node.ClassName}.Generated.cs";
9898
var relativePath = Path.Combine(tool.OutputDirectory, "Services", fileName);
9999

100100
files.Add(new GeneratedFile

0 commit comments

Comments
 (0)