Skip to content

Commit f66acf1

Browse files
committed
Warning implementation for reviewing ops
1 parent a2d1d7c commit f66acf1

3 files changed

Lines changed: 489 additions & 13 deletions

File tree

lib/migration_generator/migration_generator.ex

Lines changed: 92 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,14 @@ defmodule AshPostgres.MigrationGenerator do
7474
extension_migration_files =
7575
create_extension_migrations(repos, opts)
7676

77-
tenant_migration_files =
77+
{tenant_migration_files, tenant_review_flags} =
7878
create_migrations(tenant_snapshots, opts, true, snapshots, unmanaged_tenant_snapshots)
7979

80-
migration_files =
80+
{migration_files, global_review_flags} =
8181
create_migrations(snapshots, opts, false, [], unmanaged_snapshots)
8282

83+
review_flags = merge_review_flag_maps(tenant_review_flags, global_review_flags)
84+
8385
case extension_migration_files ++ tenant_migration_files ++ migration_files do
8486
[] ->
8587
if !opts.check || opts.dry_run do
@@ -91,6 +93,10 @@ defmodule AshPostgres.MigrationGenerator do
9193
:ok
9294

9395
files ->
96+
if !(opts.check or opts.quiet or opts.no_shell?) do
97+
emit_review_warnings(review_flags)
98+
end
99+
94100
cond do
95101
opts.check ->
96102
raise Ash.Error.Framework.PendingCodegen,
@@ -460,7 +466,7 @@ defmodule AshPostgres.MigrationGenerator do
460466
) do
461467
snapshots
462468
|> Enum.group_by(& &1.repo)
463-
|> Enum.flat_map(fn {repo, snapshots} ->
469+
|> Enum.reduce({[], initial_review_flags()}, fn {repo, snapshots}, {files_acc, flags_acc} ->
464470
deduped = deduplicate_snapshots(snapshots, opts, non_tenant_snapshots)
465471

466472
managed_table_keys =
@@ -539,12 +545,13 @@ defmodule AshPostgres.MigrationGenerator do
539545
|> Enum.concat(drop_operations)
540546
|> Enum.uniq()
541547

542-
operations
543-
|> case do
548+
case operations do
544549
[] ->
545-
[]
550+
{files_acc, flags_acc}
546551

547552
operations ->
553+
repo_flags = classify_operations(operations)
554+
548555
dev_migrations = get_dev_migrations(opts, tenant?, repo)
549556

550557
if !opts.dev and dev_migrations != [] do
@@ -582,16 +589,89 @@ defmodule AshPostgres.MigrationGenerator do
582589
operations_to_migrations(public_operations, repo, opts, false)
583590
end
584591

585-
migrations
586-
|> Enum.concat(create_new_snapshot(snapshots, repo_name(repo), opts, tenant?))
587-
|> then(fn files ->
588-
remove_orphan_snapshots(orphan_snapshots, opts)
589-
files
590-
end)
592+
files =
593+
migrations
594+
|> Enum.concat(create_new_snapshot(snapshots, repo_name(repo), opts, tenant?))
595+
|> then(fn files ->
596+
remove_orphan_snapshots(orphan_snapshots, opts)
597+
files
598+
end)
599+
600+
{files_acc ++ files, merge_review_flag_maps(flags_acc, repo_flags)}
591601
end
592602
end)
593603
end
594604

605+
defp emit_review_warnings(review_flags) do
606+
shell = Mix.shell()
607+
608+
review_flags
609+
|> review_warning_messages()
610+
|> Enum.each(&shell.info/1)
611+
end
612+
613+
defp review_warning_messages(review_flags) do
614+
[
615+
review_baseline_message(),
616+
review_commented_safeguards_message(review_flags),
617+
review_destructive_message(review_flags)
618+
]
619+
|> Enum.reject(&is_nil/1)
620+
end
621+
622+
defp review_baseline_message do
623+
"Please always manually review the generated migrations for correctness."
624+
end
625+
626+
defp review_commented_safeguards_message(%{commented_safeguards?: true}) do
627+
"Warning: there are migration steps commented out and in need of manual review."
628+
end
629+
630+
defp review_commented_safeguards_message(_), do: nil
631+
632+
defp review_destructive_message(%{destructive_uncommented?: true}) do
633+
"Warning: this migration includes destructive operations (e.g. drops or column removals). Review carefully before migrating."
634+
end
635+
636+
defp review_destructive_message(_), do: nil
637+
638+
defp classify_operations(operations) do
639+
Enum.reduce(operations, initial_review_flags(), &merge_review_flags/2)
640+
end
641+
642+
defp initial_review_flags do
643+
%{commented_safeguards?: false, destructive_uncommented?: false}
644+
end
645+
646+
defp merge_review_flags(op, acc) do
647+
acc
648+
|> Map.update!(:commented_safeguards?, &(&1 or commented_safeguard?(op)))
649+
|> Map.update!(:destructive_uncommented?, &(&1 or destructive_uncommented?(op)))
650+
end
651+
652+
defp merge_review_flag_maps(a, b) do
653+
%{
654+
commented_safeguards?: a.commented_safeguards? or b.commented_safeguards?,
655+
destructive_uncommented?: a.destructive_uncommented? or b.destructive_uncommented?
656+
}
657+
end
658+
659+
defp commented_safeguard?(%{commented?: true}), do: true
660+
defp commented_safeguard?(_), do: false
661+
662+
defp destructive_uncommented?(%Operation.DropTable{}), do: true
663+
defp destructive_uncommented?(%Operation.RemoveAttribute{commented?: false}), do: true
664+
defp destructive_uncommented?(%Operation.RemovePrimaryKey{}), do: true
665+
defp destructive_uncommented?(%Operation.RemovePrimaryKeyDown{commented?: false}), do: true
666+
defp destructive_uncommented?(%Operation.DropForeignKey{}), do: true
667+
defp destructive_uncommented?(%Operation.RemoveCustomStatement{}), do: true
668+
defp destructive_uncommented?(%Operation.RemoveCustomIndex{}), do: true
669+
defp destructive_uncommented?(%Operation.RemoveReferenceIndex{}), do: true
670+
defp destructive_uncommented?(%Operation.RemoveUniqueIndex{}), do: true
671+
defp destructive_uncommented?(%Operation.RemoveCheckConstraint{}), do: true
672+
defp destructive_uncommented?(%Operation.AddPrimaryKeyDown{remove_old?: true}), do: true
673+
defp destructive_uncommented?(_), do: false
674+
595675
defp operations_to_migrations([], _repo, _opts, _tenant?), do: []
596676

597677
defp operations_to_migrations(operations, repo, opts, tenant?) do

0 commit comments

Comments
 (0)