### Install StewardEF .NET Tool Source: https://github.com/pdevito3/stewardef/blob/main/README.md Installs the StewardEF command-line tool globally using the .NET CLI. This command makes the `steward` executable available on your system. ```bash dotnet tool install -g StewardEF ``` -------------------------------- ### Build and Package .NET Project Source: https://github.com/pdevito3/stewardef/blob/main/CLAUDE.md Demonstrates the commands to build, package, and install the .NET project locally for testing and development purposes. It covers building, creating a NuGet package, installing the tool locally, and uninstalling the tool. ```bash # Build the project dotnet build # Create NuGet package dotnet pack -c Release # Install tool locally for testing dotnet tool install --global --add-source ./StewardEF/nupkg StewardEF # Uninstall tool dotnet tool uninstall -g StewardEF ``` -------------------------------- ### Run StewardEF from Source with .NET Source: https://github.com/pdevito3/stewardef/blob/main/CLAUDE.md Demonstrates running the StewardEF tool directly from source code without installing. It also includes commands to clean build artifacts. ```bash # Run from source without installing dotnet run --project StewardEF/StewardEF.csproj -- squash -d path/to/test/migrations # Clean build artifacts dotnet clean ``` -------------------------------- ### Automated Update Notification via GitHub Releases - C# Source: https://context7.com/pdevito3/stewardef/llms.txt The VersionChecker class in C# automatically checks GitHub releases for newer versions of StewardEF. It compares the installed version with the latest release version and displays an update notification if the installed version is outdated. The check is performed asynchronously and fails silently to avoid interrupting the user's workflow. This ensures users are prompted to update to the latest version, benefiting from new features and bug fixes. ```csharp internal static class VersionChecker { private const string DefaultVersion = "0.0.0"; public static async Task CheckForLatestVersion() { try { var installedVersion = GetInstalledStewardEfVersion(); var latestReleaseVersion = await GetLatestReleaseVersion(); var result = new Version(installedVersion).CompareTo(new Version(latestReleaseVersion)); if (result < 0) { AnsiConsole.MarkupLine($"{@Environment.NewLine}[bold seagreen2]This StewardEF version '{installedVersion}' is older than that of the runtime '{latestReleaseVersion}'. Update the tools for the latest features and bug fixes (`dotnet tool update -g stewardef`).[/]{@Environment.NewLine}"); } } catch (Exception) { // Fail silently to not interrupt user workflow } } private static async Task GetLatestReleaseVersion() { var latestReleasePath = "https://github.com/pdevito3/stewardef/releases/latest"; using var client = new HttpClient(); client.DefaultRequestHeaders.Add("Accept", "text/html"); var response = await client.GetAsync(latestReleasePath); response.EnsureSuccessStatusCode(); var redirectUrl = response?.RequestMessage?.RequestUri; var version = redirectUrl?.ToString().Split('/').Last().Replace("v", "") ?? DefaultVersion; return version; } private static string GetInstalledStewardEfVersion() { var installedVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? DefaultVersion; installedVersion = installedVersion[0..^2]; // Remove last two version segments return installedVersion; } } ``` -------------------------------- ### Generate EF Core Migration SQL Scripts (C#) Source: https://context7.com/pdevito3/stewardef/llms.txt Executes the 'dotnet ef migrations script' command to generate SQL statements for EF Core migration Up and Down operations. It requires the project path, a starting migration ID, and an ending migration ID. It returns the generated SQL as a string or null if an error occurs. This function is useful for converting migrations to SQL scripts. ```csharp private static string? ExecuteEfScript(string fromMigration, string toMigration, string projectPath) { try { var startInfo = new ProcessStartInfo { FileName = "dotnet", Arguments = $"ef migrations script {fromMigration} {toMigration} --project \"{projectPath}\" --no-build", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; using var process = Process.Start(startInfo); if (process == null) { AnsiConsole.MarkupLine("[red]Failed to start dotnet ef process[/]"); return null; } var output = process.StandardOutput.ReadToEnd(); var error = process.StandardError.ReadToEnd(); process.WaitForExit(); if (process.ExitCode != 0) { AnsiConsole.MarkupLine($"[red]dotnet ef script failed: {error}[/]"); return null; } return output; } catch (Exception ex) { AnsiConsole.MarkupLine($"[red]Error executing dotnet ef: {ex.Message}[/]"); return null; } } ``` -------------------------------- ### Run StewardEF Tool with Command Line Options Source: https://github.com/pdevito3/stewardef/blob/main/CLAUDE.md Illustrates how to execute the StewardEF tool with different command-line options. It covers running the squash command, specifying a migration directory, filtering by year, and targeting a specific migration. ```bash # Run the tool (after installing locally) steward squash -d path/to/migrations # With year filter steward squash -d path/to/migrations -y 2023 # With target migration steward squash -d path/to/migrations -t MigrationName ``` -------------------------------- ### Find Project File - C# Source: https://context7.com/pdevito3/stewardef/llms.txt Searches up the directory tree to find the .csproj file for dotnet ef command execution. It can take an explicit project path or discover the file automatically, preferring non-test projects if multiple exist. ```csharp using System; using System.IO; using System.Linq; using Spectre.Console; public static class ProjectFinder { // Search for project file starting from migrations directory public static void ExampleUsage1() { var migrationsDir = "/home/user/MyApp/Data/Migrations"; var projectPath = FindProjectFile(migrationsDir); // Returns: "/home/user/MyApp/MyApp.csproj" Console.WriteLine($"Found project: {projectPath}"); } // With explicit project path public static void ExampleUsage2() { var migrationsDir = "/home/user/MyApp/Data/Migrations"; var explicitPath = "/home/user/MyApp/MyApp.csproj"; var projectPath = FindProjectFile(migrationsDir, explicitPath); // Returns: "/home/user/MyApp/MyApp.csproj" (validated) Console.WriteLine($"Found project: {projectPath}"); } // Multiple .csproj files - prefers non-test projects public static void ExampleUsage3() { // Directory contains: MyApp.csproj, MyApp.Tests.csproj var migrationsDir = "/home/user/MyApp/Data/Migrations"; var projectPath = FindProjectFile(migrationsDir); // Returns: "/home/user/MyApp/MyApp.csproj" (excludes .Tests) Console.WriteLine($"Found project: {projectPath}"); } internal static string? FindProjectFile(string migrationsDirectory, string? explicitProjectPath = null) { // Validate explicit path if provided if (!string.IsNullOrWhiteSpace(explicitProjectPath)) { if (File.Exists(explicitProjectPath) && explicitProjectPath.EndsWith(".csproj")) { return Path.GetFullPath(explicitProjectPath); } AnsiConsole.MarkupLine($"[yellow]Warning: Specified project file not found: {explicitProjectPath}[/]"); } // Search up directory tree var currentDir = new DirectoryInfo(Path.GetFullPath(migrationsDirectory)); while (currentDir != null) { var projectFiles = currentDir.GetFiles("*.csproj"); if (projectFiles.Length > 0) { // Prefer non-test projects var projectFile = projectFiles.Length == 1 ? projectFiles[0] : projectFiles.FirstOrDefault(f => !f.Name.Contains(".Tests")) ?? projectFiles[0]; return projectFile.FullName; } currentDir = currentDir.Parent; } return null; } } ``` -------------------------------- ### Squash EF Core Migrations - Bash Commands Source: https://context7.com/pdevito3/stewardef/llms.txt Demonstrates how to use the 'steward squash' command to consolidate Entity Framework Core migrations. It covers basic usage, filtering by year, and targeting a specific migration. The tool intelligently handles C# code and can detect/convert rename operations to SQL. ```bash # Basic squash - combines all migrations steward squash ./Migrations # Filter by year - only squash migrations from 2023 steward squash ./MyProject/Data/Migrations -y 2023 # Target migration - squash up to specific migration steward squash ./Migrations -t AddUserTable steward squash ./Migrations -t 20230615123456_AddUserTable # Example output: # Squashing 15 migration files... # Migrations squashed successfully! ✨ # With automatic rename detection and SQL conversion: # Squashing 15 migration files... # Migrations squashed successfully! ✨ # ⚠ Detected rename operations in squashed migration # Converting to SQL script format... # Found project: MyApp.csproj # ✓ Successfully converted to SQL format ``` -------------------------------- ### Convert EF Core Migration to SQL - Bash Commands Source: https://context7.com/pdevito3/stewardef/llms.txt Illustrates the 'steward convert-to-sql' command for transforming C# Entity Framework Core migrations into SQL scripts. This is useful for migrations involving rename operations or for generating deployment scripts. It supports converting the latest migration, a specific migration by name, or when a project path is explicitly provided. ```bash # Convert the most recent migration steward convert-to-sql ./Migrations # Convert with explicit project path steward convert-to-sql ./Migrations -p ./MyApp.csproj # Convert a specific migration by name steward convert-to-sql ./Migrations -m AddUserTable steward convert-to-sql ./Migrations -m 20231201120000_AddUserTable # Example output: # Using project: MyApp.csproj # Converting migration to SQL: 20231201120000_AddUserTable.cs # Generating SQL scripts... # Migration converted to SQL successfully! ✨ # The migration file will be modified from: # protected override void Up(MigrationBuilder migrationBuilder) # { # migrationBuilder.RenameColumn( # name: "OldName", # table: "Users", # newName: "NewName"); # } # To: # protected override void Up(MigrationBuilder migrationBuilder) # { # migrationBuilder.Sql(@" # EXEC sp_rename 'Users.OldName', 'NewName', 'COLUMN'; # "); # } ``` -------------------------------- ### Replace C# Migration Methods with SQL Scripts - C# Source: https://context7.com/pdevito3/stewardef/llms.txt This C# function, ReplaceWithSqlScript, converts C# migration methods (Up and Down) into SQL script calls using migrationBuilder.Sql(). It takes the migration file path and SQL strings for up and down migrations as input. It reads the migration file, constructs the SQL script content with verbatim strings, and overwrites the original migration file with the updated content. This is useful for managing database schema changes with SQL scripts instead of C# code. ```csharp private static void ReplaceWithSqlScript(string migrationFilePath, string upSql, string downSql) { var lines = File.ReadAllLines(migrationFilePath).ToList(); var upSqlContent = $" migrationBuilder.Sql(@\"\n{upSql.Replace("\"", "\"\"")}\n \");"; ReplaceMethodContent(lines, "Up", upSqlContent); var downSqlContent = $" migrationBuilder.Sql(@\"\n{downSql.Replace("\"", "\"\"")}\n \");"; ReplaceMethodContent(lines, "Down", downSqlContent); File.WriteAllLines(migrationFilePath, lines); } ``` -------------------------------- ### C# BraceCounter: Context-Aware Brace Counting Source: https://context7.com/pdevito3/stewardef/llms.txt This C# code defines a BraceCounter class that counts braces ('{' and '}') while intelligently skipping those within strings (verbatim and regular), multi-line comments, and single-line comments. It handles state transitions for these contexts to ensure accurate counting in complex code lines. Dependencies: None. ```csharp private class BraceCounter { private bool _inVerbatimString = false; private bool _inMultiLineComment = false; public int CountBraces(string line) { int count = 0; bool inString = false; bool inChar = false; bool inSingleLineComment = false; for (int i = 0; i < line.Length; i++) { char c = line[i]; char next = i + 1 < line.Length ? line[i + 1] : '\0'; char prev = i > 0 ? line[i - 1] : '\0'; // Handle state transitions for multi-line constructs if (_inMultiLineComment) { if (c == '*' && next == '/') { _inMultiLineComment = false; i++; } continue; } if (_inVerbatimString) { if (c == '"' && next != '"') _inVerbatimString = false; else if (c == '"' && next == '"') i++; // Skip escaped quote continue; } // Detect context entry points if (!inString && !inChar && c == '/' && next == '*') { _inMultiLineComment = true; i++; continue; } if (!inString && !inChar && c == '/' && next == '/') { break; // Rest of line is comment } if (!inString && !inChar && c == '@' && next == '"') { _inVerbatimString = true; i++; continue; } if (!inChar && c == '"' && prev != '\') inString = !inString; if (!inString && c == ''' && prev != '\') inChar = !inChar; // Count braces only in normal code context if (!inString && !inChar && !inSingleLineComment && !_inVerbatimString && !_inMultiLineComment) { if (c == '{') count++; else if (c == '}') count--; } } return count; } } ``` -------------------------------- ### StewardEF Squash Command Settings - C# Source: https://context7.com/pdevito3/stewardef/llms.txt Defines the settings model for the 'squash' command in StewardEF, using Spectre.Console.Cli. It includes properties for the migrations directory, an optional year filter, and a target migration name. This class handles parsing command-line arguments for the squashing operation. ```csharp using Spectre.Console.Cli; internal class SquashMigrationsCommand : Command { public class Settings : CommandSettings { [CommandArgument(0, "[MigrationsDirectory]")] public string? MigrationsDirectory { get; set; } [CommandOption("-y|--year")] public int? Year { get; set; } [CommandOption("-t|--target")] public string? TargetMigration { get; set; } } public override int Execute(CommandContext context, Settings settings, CancellationToken cancellationToken) { var directory = settings.MigrationsDirectory ?? AnsiConsole.Ask("[green]Enter the migrations directory path:[/]"); if (string.IsNullOrWhiteSpace(directory) || !Directory.Exists(directory)) { AnsiConsole.MarkupLine("[red]The specified directory is invalid.[/]"); return 1; } SquashMigrations(directory, settings.Year, settings.TargetMigration); return 0; } } // Usage via Spectre.Console.Cli framework: // var app = new CommandApp(); // app.Configure(config => // { // config.AddCommand("squash") // .WithDescription("Squashes EF migrations into the first migration.") // .WithExample(new[] { "squash", "path/to/migrations" }); // }); // app.Run(args); ``` -------------------------------- ### Squash All EF Migrations Source: https://github.com/pdevito3/stewardef/blob/main/README.md Combines all EF Core migrations in the specified directory into a single migration file. This command is useful for cleaning up a lengthy migration history and speeding up builds. It operates on the C# code of the migrations. ```bash steward squash path/to/migrations ``` -------------------------------- ### StewardEF Migration Squashing Process (Conceptual) Source: https://github.com/pdevito3/stewardef/blob/main/README.md Illustrates the internal steps StewardEF takes to squash migrations. It aggregates C# code, manages using statements, updates designer files, and cleans up intermediate files. This process is automated by the `steward squash` command. ```text > 1. C# Aggregation: Combines the Up and Down methods across all migration files using standard C# code concatenation > 2. Using Statements: Collects using statements from all migrations, ensuring no dependencies are missed > 3. Designer File Update: Renames the latest designer file to match the first migration and updates its metadata > 4. Cleanup: Deletes all intermediate migrations, leaving only the squashed first migration > 5. Automatic Rename Detection (post-squash): Scans the squashed result for rename operations (RenameColumn, RenameTable, RenameIndex) > 6. SQL Conversion (if needed): If rename operations are detected, automatically converts the squashed migration to SQL format ``` -------------------------------- ### Aggregate C# Migration Method Content Source: https://context7.com/pdevito3/stewardef/llms.txt Combines the extracted method contents from multiple C# migration files into a single block. It labels each section with the source file name and can optionally collect all 'using' statements from the processed files. This function requires an enumerable of file paths, the method name to extract ('Up' or 'Down'), and a boolean to indicate whether to collect using statements. It returns an object containing the aggregated content and a list of unique using statements. ```csharp private static AggregatedMethodResult GetAggregatedMethodContent( IEnumerable files, string methodName, bool collectUsings = false) { var result = new AggregatedMethodResult(); var aggregatedContent = new StringBuilder(); foreach (var file in files) { var fileName = Path.GetFileName(file); var migrationLines = File.ReadAllLines(file); if (collectUsings) { var usings = ExtractUsingStatements(migrationLines); foreach (var u in usings) result.UsingStatements.Add(u); } var methodContent = ExtractMethodContent(migrationLines, methodName); if (!string.IsNullOrEmpty(methodContent)) { aggregatedContent.AppendLine("{"); aggregatedContent.AppendLine($"// {fileName}"); aggregatedContent.AppendLine(methodContent); aggregatedContent.AppendLine("}"); aggregatedContent.AppendLine(); } } result.AggregatedContent = aggregatedContent.ToString(); return result; } ``` -------------------------------- ### StewardEF Handling of Rename Operations Source: https://github.com/pdevito3/stewardef/blob/main/README.md Demonstrates how StewardEF automatically handles migrations containing rename operations by converting the squashed migration to SQL scripts. This prevents common errors related to schema changes and designer metadata mismatches. The process involves generating SQL using `dotnet ef migrations script`. ```text > Squashing 15 migration files... > Migrations squashed successfully! ✨ > ⚠ Detected rename operations in squashed migration > Converting to SQL script format... > Found project: MyApp.csproj > ✓ Successfully converted to SQL format > > The tool automatically: > 1. Squashes migrations normally using C# code concatenation > 2. Checks the squashed result for problematic rename operations > 3. If found, locates your .csproj file (searches up the directory tree) > 4. Generates SQL scripts using `dotnet ef migrations script 0 ` > 5. Replaces the squashed migration content with `migrationBuilder.Sql()` calls containing the generated SQL ``` -------------------------------- ### Extract C# Migration Method Content Source: https://context7.com/pdevito3/stewardef/llms.txt Extracts the content of 'Up' or 'Down' methods from C# migration files. It uses brace-level tracking to accurately identify the method body, respecting C# syntax and contexts. This method requires the file lines and the name of the method to extract. It returns the method's content without the signature and braces. ```csharp private static string ExtractMethodContent(string[] lines, string methodName) { var methodSignature = $"protected override void {methodName}(MigrationBuilder migrationBuilder)"; int methodStartIndex = -1; for (int i = 0; i < lines.Length; i++) { if (lines[i].Contains(methodSignature)) { methodStartIndex = i; break; } } if (methodStartIndex == -1) return string.Empty; var methodContent = new StringBuilder(); var braceCounter = new BraceCounter(); int braceLevel = 0; bool methodStarted = false; for (int i = methodStartIndex; i < lines.Length; i++) { var line = lines[i]; if (!methodStarted) { if (line.Contains("{")) { methodStarted = true; braceLevel += braceCounter.CountBraces(line); int braceIndex = line.IndexOf('{'); if (braceIndex + 1 < line.Length) { var afterBrace = line.Substring(braceIndex + 1); if (!string.IsNullOrWhiteSpace(afterBrace)) methodContent.AppendLine(afterBrace); } } } else { braceLevel += braceCounter.CountBraces(line); if (braceLevel == 0) break; else methodContent.AppendLine(line); } } return methodContent.ToString().Trim(); } ``` -------------------------------- ### Manage C# Using Statements - UpdateUsingStatements Source: https://context7.com/pdevito3/stewardef/llms.txt Merges and deduplicates using statements in a C# file. It handles both scoped and block-style namespaces and sorts the using statements alphabetically. It requires the System.Collections.Generic and System.Linq namespaces. ```csharp private static void UpdateUsingStatements(List lines, HashSet usingStatements) { var namespaceIndex = lines.FindIndex(line => line.TrimStart().StartsWith("namespace ")); if (namespaceIndex == -1) { AnsiConsole.MarkupLine("[red]No namespace declaration found in the file.[/]"); return; } var namespaceLine = lines[namespaceIndex]; var isScopedNamespace = namespaceLine.TrimEnd().EndsWith(";"); var insertIndex = isScopedNamespace ? namespaceIndex + 1 : namespaceIndex + 2; // Remove existing using statements while (insertIndex < lines.Count && lines[insertIndex].TrimStart().StartsWith("using ")) lines.RemoveAt(insertIndex); // Sort and insert new usings var sortedUsings = usingStatements.OrderBy(u => u).ToList(); if (isScopedNamespace) { sortedUsings.Insert(0, ""); sortedUsings.Add(Environment.NewLine); lines.InsertRange(insertIndex, sortedUsings); } else { var indentation = GetIndentation(lines[namespaceIndex]) + " "; var indentedUsings = sortedUsings.Select(u => !string.IsNullOrEmpty(u) ? indentation + u : u).ToList(); indentedUsings.Add(Environment.NewLine); lines.InsertRange(insertIndex, indentedUsings); } } ``` -------------------------------- ### Update C# Designer File - UpdateDesignerFile Source: https://context7.com/pdevito3/stewardef/llms.txt Updates the Migration attribute and partial class name in a C# designer file to match a squashed migration. It reads the designer file content, extracts the new migration name and class name from a specified migration file, and then uses regular expressions to update the relevant lines. This function requires System.IO and System.Text.RegularExpressions. ```csharp private static void UpdateDesignerFile(string designerFilePath, string firstMigrationFilePath) { var designerContent = File.ReadAllText(designerFilePath); var firstMigrationFileName = Path.GetFileNameWithoutExtension(firstMigrationFilePath); // Extract class name (everything after timestamp and underscore) var className = ExtractMigrationClassName(firstMigrationFileName); // Update Migration attribute designerContent = Regex.Replace( designerContent, @"'[Migration'\s*\(\s*'[^'"]*'\s*\)'']", $"[Migration(\"{firstMigrationFileName}\")]"); // Update class name (handles underscores in migration names) designerContent = Regex.Replace( designerContent, @"partial class [\w_]+", $"partial class {className}"); File.WriteAllText(designerFilePath, designerContent); } ``` -------------------------------- ### Detect Rename Operations in EF Migrations (C#) Source: https://context7.com/pdevito3/stewardef/llms.txt Scans C# migration files to identify rename operations (RenameColumn, RenameTable, RenameIndex) that may require SQL conversion to prevent issues with designer files. It takes a list of migration file paths as input and returns a boolean indicating whether problematic renames were found. Excludes files ending with '.Designer.cs'. ```csharp internal static bool HasProblematicRenameOperations(IEnumerable migrationFiles) { foreach (var file in migrationFiles) { if (file.EndsWith(".Designer.cs", StringComparison.OrdinalIgnoreCase)) continue; var content = File.ReadAllText(file); if (content.Contains("RenameColumn") || content.Contains("RenameTable") || content.Contains("RenameIndex")) { return true; } } return false; } ``` -------------------------------- ### Squash EF Migrations to a Target Migration Name Source: https://github.com/pdevito3/stewardef/blob/main/README.md Squashes EF Core migrations up to a specific migration name. This can be the full name (including timestamp) or a partial, case-insensitive match. The `-t` flag is used for specifying the target migration. ```bash steward squash path/to/migrations -t 20230615000000_AddUserTable ``` ```bash steward squash path/to/migrations -t AddUserTable ``` -------------------------------- ### Squash EF Migrations Up to a Specific Year Source: https://github.com/pdevito3/stewardef/blob/main/README.md Squashes EF Core migrations, but only includes those up to the specified year. This allows for partial squashing, keeping recent migrations separate if needed. The `-y` flag specifies the target year. ```bash steward squash path/to/migrations -y 2023 ``` -------------------------------- ### Extract C# Migration Class Name - ExtractMigrationClassName Source: https://context7.com/pdevito3/stewardef/llms.txt Helper function to extract the migration class name from a migration file name. It assumes the standard Entity Framework migration file format (YYYYMMDDHHMMSS_MigrationName). If the pattern is not matched, it falls back to splitting by underscore. Requires System.Text.RegularExpressions. ```csharp private static string ExtractMigrationClassName(string migrationFileName) { // EF format: YYYYMMDDHHMMSS_MigrationName var match = Regex.Match(migrationFileName, @"'^\d{14}_(.+)$'"); return match.Success ? match.Groups[1].Value : migrationFileName.Split('_').Last(); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.