From ab6ed5a08d9622c34b2aab514d45690d3424b47d Mon Sep 17 00:00:00 2001 From: Lucas Pope Date: Sat, 28 Jun 2025 20:07:09 -0300 Subject: [PATCH 1/3] Auto-convert spaces to underscores in migration names - Replace spaces with underscores automatically in mix ecto.gen.migration - Maintain existing validation for other invalid characters - Improve UX by handling common user input patterns - Preserve backward compatibility for existing workflows --- lib/mix/tasks/ecto.gen.migration.ex | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/mix/tasks/ecto.gen.migration.ex b/lib/mix/tasks/ecto.gen.migration.ex index 51d2bfce..ccdbe0b7 100644 --- a/lib/mix/tasks/ecto.gen.migration.ex +++ b/lib/mix/tasks/ecto.gen.migration.ex @@ -68,7 +68,8 @@ defmodule Mix.Tasks.Ecto.Gen.Migration do {opts, [name]} -> ensure_repo(repo, args) path = opts[:migrations_path] || Path.join(source_repo_priv(repo), "migrations") - base_name = "#{underscore(name)}.exs" + normalized_name = normalize_migration_name(name) + base_name = "#{underscore(normalized_name)}.exs" file = Path.join(path, "#{timestamp()}_#{base_name}") unless File.dir?(path), do: create_directory(path) @@ -76,13 +77,13 @@ defmodule Mix.Tasks.Ecto.Gen.Migration do if Path.wildcard(fuzzy_path) != [] do Mix.raise( - "migration can't be created, there is already a migration file with name #{name}." + "migration can't be created, there is already a migration file with name #{normalized_name}." ) end # The :change option may be used by other tasks but not the CLI assigns = [ - mod: Module.concat([repo, Migrations, camelize(name)]), + mod: Module.concat([repo, Migrations, camelize(normalized_name)]), change: opts[:change] ] @@ -118,6 +119,12 @@ defmodule Mix.Tasks.Ecto.Gen.Migration do end end + defp normalize_migration_name(name) do + name + |> String.replace(~r/\s+/, "_") + |> String.trim("_") + end + embed_template(:migration, """ defmodule <%= inspect @mod %> do use <%= inspect migration_module() %> From 434063e2c77029920ce28cd43e49bbe79dad22ad Mon Sep 17 00:00:00 2001 From: Lucas Pope Date: Sat, 28 Jun 2025 20:07:46 -0300 Subject: [PATCH 2/3] Add tests for space-to-underscore conversion in migration names - Test basic space conversion functionality - Test edge cases with multiple and leading/trailing spaces - Verify proper module name generation with converted names - Ensure existing functionality remains intact --- test/mix/tasks/ecto.gen.migration_test.exs | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/mix/tasks/ecto.gen.migration_test.exs b/test/mix/tasks/ecto.gen.migration_test.exs index ca16f605..58954564 100644 --- a/test/mix/tasks/ecto.gen.migration_test.exs +++ b/test/mix/tasks/ecto.gen.migration_test.exs @@ -56,6 +56,32 @@ defmodule Mix.Tasks.Ecto.Gen.MigrationTest do assert name =~ ~r/^\d{14}_my_migration\.exs$/ end + test "converts spaces to underscores in migration name" do + [path] = run(["-r", to_string(Repo), "add posts table"]) + assert Path.basename(path) =~ ~r/^\d{14}_add_posts_table\.exs$/ + + assert_file(path, fn file -> + assert file =~ "defmodule Mix.Tasks.Ecto.Gen.MigrationTest.Repo.Migrations.AddPostsTable do" + end) + end + + test "handles multiple spaces and edge cases in migration names" do + [path1] = run(["-r", to_string(Repo), " add posts table "]) + assert Path.basename(path1) =~ ~r/^\d{14}_add_posts_table\.exs$/ + + [path2] = run(["-r", to_string(Repo), "create user accounts"]) + assert Path.basename(path2) =~ ~r/^\d{14}_create_user_accounts\.exs$/ + + assert_file(path1, fn file -> + assert file =~ "defmodule Mix.Tasks.Ecto.Gen.MigrationTest.Repo.Migrations.AddPostsTable do" + end) + + assert_file(path2, fn file -> + assert file =~ + "defmodule Mix.Tasks.Ecto.Gen.MigrationTest.Repo.Migrations.CreateUserAccounts do" + end) + end + test "custom migrations_path" do dir = Path.join([unquote(tmp_path), "custom_migrations"]) [path] = run(["-r", to_string(Repo), "--migrations-path", dir, "custom_path"]) From 7b3cdf56b0014b498017b3cfca71402b185018c6 Mon Sep 17 00:00:00 2001 From: Lucas Pope Date: Sat, 28 Jun 2025 21:26:16 -0300 Subject: [PATCH 3/3] Fix CLI argument handling for multi-word migration names Join multiple arguments before normalizing spaces to underscores. Updates tests to use realistic CLI argument patterns. --- lib/mix/tasks/ecto.gen.migration.ex | 5 +++-- test/mix/tasks/ecto.gen.migration_test.exs | 22 ++++++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/mix/tasks/ecto.gen.migration.ex b/lib/mix/tasks/ecto.gen.migration.ex index ccdbe0b7..becfef6f 100644 --- a/lib/mix/tasks/ecto.gen.migration.ex +++ b/lib/mix/tasks/ecto.gen.migration.ex @@ -65,10 +65,11 @@ defmodule Mix.Tasks.Ecto.Gen.Migration do Enum.map(repos, fn repo -> case OptionParser.parse!(args, strict: @switches, aliases: @aliases) do - {opts, [name]} -> + {opts, [name | rest]} -> ensure_repo(repo, args) path = opts[:migrations_path] || Path.join(source_repo_priv(repo), "migrations") - normalized_name = normalize_migration_name(name) + full_name = Enum.join([name | rest], " ") + normalized_name = normalize_migration_name(full_name) base_name = "#{underscore(normalized_name)}.exs" file = Path.join(path, "#{timestamp()}_#{base_name}") unless File.dir?(path), do: create_directory(path) diff --git a/test/mix/tasks/ecto.gen.migration_test.exs b/test/mix/tasks/ecto.gen.migration_test.exs index 58954564..cdf34476 100644 --- a/test/mix/tasks/ecto.gen.migration_test.exs +++ b/test/mix/tasks/ecto.gen.migration_test.exs @@ -57,7 +57,7 @@ defmodule Mix.Tasks.Ecto.Gen.MigrationTest do end test "converts spaces to underscores in migration name" do - [path] = run(["-r", to_string(Repo), "add posts table"]) + [path] = run(["-r", to_string(Repo), "add", "posts", "table"]) assert Path.basename(path) =~ ~r/^\d{14}_add_posts_table\.exs$/ assert_file(path, fn file -> @@ -65,15 +65,16 @@ defmodule Mix.Tasks.Ecto.Gen.MigrationTest do end) end - test "handles multiple spaces and edge cases in migration names" do - [path1] = run(["-r", to_string(Repo), " add posts table "]) - assert Path.basename(path1) =~ ~r/^\d{14}_add_posts_table\.exs$/ + test "handles multiple arguments as migration name components" do + [path1] = run(["-r", to_string(Repo), "add", "posts", "table", "with", "index"]) + assert Path.basename(path1) =~ ~r/^\d{14}_add_posts_table_with_index\.exs$/ - [path2] = run(["-r", to_string(Repo), "create user accounts"]) + [path2] = run(["-r", to_string(Repo), "create", "user", "accounts"]) assert Path.basename(path2) =~ ~r/^\d{14}_create_user_accounts\.exs$/ assert_file(path1, fn file -> - assert file =~ "defmodule Mix.Tasks.Ecto.Gen.MigrationTest.Repo.Migrations.AddPostsTable do" + assert file =~ + "defmodule Mix.Tasks.Ecto.Gen.MigrationTest.Repo.Migrations.AddPostsTableWithIndex do" end) assert_file(path2, fn file -> @@ -82,6 +83,15 @@ defmodule Mix.Tasks.Ecto.Gen.MigrationTest do end) end + test "handles edge cases in migration name normalization" do + [path] = run(["-r", to_string(Repo), " add posts table "]) + assert Path.basename(path) =~ ~r/^\d{14}_add_posts_table\.exs$/ + + assert_file(path, fn file -> + assert file =~ "defmodule Mix.Tasks.Ecto.Gen.MigrationTest.Repo.Migrations.AddPostsTable do" + end) + end + test "custom migrations_path" do dir = Path.join([unquote(tmp_path), "custom_migrations"]) [path] = run(["-r", to_string(Repo), "--migrations-path", dir, "custom_path"])