From 206882ac2d0b45e0e73368f384133a588e0d130a Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Sat, 24 Aug 2024 18:18:33 +0700 Subject: [PATCH 01/20] order migrations --- lib/plausible_release.ex | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index 9d23382e765e..a4b4b633e1eb 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -25,6 +25,39 @@ defmodule Plausible.Release do IO.puts("Migrations successful!") end + # Unlike `migrate/0` above this function lists *all* pending migrations + # across all repos, sorts them into a single liss and only then runs them. + # This approach helps resolve dependencies between migrations across repos. + def interweave_sort_migrate do + prepare() + + # interweave + all_pending = + Enum.flat_map(repos(), fn repo -> + Ecto.Migrator.migrations(repo) + |> Enum.filter(fn {status, _version, _name} -> status == :down end) + |> Enum.map(fn {_status, version, name} -> {repo, _migration = {version, name}} end) + end) + + # sort + all_sorted = + Enum.sort_by(all_pending, fn {_repo, migration} -> migration end, :asc) + + # migrate + Enum.each(all_sorted, fn {repo, {version, name}} -> + [{module, _binary}] = + Code.compile_file( + "#{version}_#{name}.exs", + _relative_to = Ecto.Migrator.migrations_path(repo) + ) + + {:ok, _, _} = + Ecto.Migrator.with_repo(repo, fn repo -> + Ecto.Migrator.run(repo, [{version, module}], :up, all: true) + end) + end) + end + def pending_migrations do prepare() IO.puts("Pending migrations") From 2a53f7e751e76f0a785c657aa1ffd93d4d6c4e79 Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Mon, 26 Aug 2024 11:41:57 +0700 Subject: [PATCH 02/20] migrate in 'streaks' --- lib/plausible_release.ex | 44 ++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index a4b4b633e1eb..ad0592342498 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -25,8 +25,12 @@ defmodule Plausible.Release do IO.puts("Migrations successful!") end - # Unlike `migrate/0` above this function lists *all* pending migrations - # across all repos, sorts them into a single liss and only then runs them. + # Unlike `migrate/0` above this function: + # - lists all pending migrations across repos, + # - sorts them into a single list, + # - groups consequent migration into "streaks" by repo, + # - migrates each repo in "streak" consequently + # # This approach helps resolve dependencies between migrations across repos. def interweave_sort_migrate do prepare() @@ -36,28 +40,38 @@ defmodule Plausible.Release do Enum.flat_map(repos(), fn repo -> Ecto.Migrator.migrations(repo) |> Enum.filter(fn {status, _version, _name} -> status == :down end) - |> Enum.map(fn {_status, version, name} -> {repo, _migration = {version, name}} end) + |> Enum.map(fn {_status, version, _name} -> {repo, version} end) end) # sort all_sorted = - Enum.sort_by(all_pending, fn {_repo, migration} -> migration end, :asc) + Enum.sort_by(all_pending, fn {_repo, version} -> version end, :asc) + + # group into streaks + streaks = migration_streaks(all_sorted) # migrate - Enum.each(all_sorted, fn {repo, {version, name}} -> - [{module, _binary}] = - Code.compile_file( - "#{version}_#{name}.exs", - _relative_to = Ecto.Migrator.migrations_path(repo) - ) - - {:ok, _, _} = - Ecto.Migrator.with_repo(repo, fn repo -> - Ecto.Migrator.run(repo, [{version, module}], :up, all: true) - end) + Enum.each(streaks, fn {repo, version} -> + {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, to: version)) end) end + defp migration_streaks([{repo, version} | streaks]) do + migration_streaks(streaks, repo, version) + end + + defp migration_streaks([] = empty), do: empty + + defp migration_streaks([{repo, version} | rest], repo, _prev_version) do + migration_streaks(rest, repo, version) + end + + defp migration_streaks([{repo, version} | rest], prev_repo, prev_version) do + [{prev_repo, prev_version} | migration_streaks(rest, repo, version)] + end + + defp migration_streaks([], repo, version), do: [{repo, version}] + def pending_migrations do prepare() IO.puts("Pending migrations") From 864f4ccc7b5d600a748d7ab0ae8567b46a1ff1f8 Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Mon, 26 Aug 2024 11:49:21 +0700 Subject: [PATCH 03/20] cleanup --- lib/plausible_release.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index ad0592342498..376f2ee46e2b 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -33,8 +33,6 @@ defmodule Plausible.Release do # # This approach helps resolve dependencies between migrations across repos. def interweave_sort_migrate do - prepare() - # interweave all_pending = Enum.flat_map(repos(), fn repo -> @@ -56,6 +54,7 @@ defmodule Plausible.Release do end) end + @doc false defp migration_streaks([{repo, version} | streaks]) do migration_streaks(streaks, repo, version) end From 1e63f92313735a09cba71c47093558de9c0631ed Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Mon, 26 Aug 2024 11:52:17 +0700 Subject: [PATCH 04/20] docs --- lib/plausible_release.ex | 179 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 166 insertions(+), 13 deletions(-) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index 376f2ee46e2b..6617dadf1f07 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -25,14 +25,166 @@ defmodule Plausible.Release do IO.puts("Migrations successful!") end - # Unlike `migrate/0` above this function: - # - lists all pending migrations across repos, - # - sorts them into a single list, - # - groups consequent migration into "streaks" by repo, - # - migrates each repo in "streak" consequently - # - # This approach helps resolve dependencies between migrations across repos. - def interweave_sort_migrate do + @doc """ + Unlike `migrate/0` above this function: + - lists all pending migrations across repos, + - sorts them into a single list, + - groups consequent migration into "streaks" by repo, + - migrates each repo in "streak" consequently + + For examples, assuming wi have the following migrations across two repos: + + priv/repo/migrations/ + - 20230530161856_add_enable_feature_fields_for_site.exs + - 20230724131709_change_allowed_event_props_type.exs + - 20230802081520_cascade_delete_user.exs + - 20230914071244_fix_broken_goals.exs + - 20230914071245_goals_unique.exs + - 20230925072840_plugins_api_tokens.exs + - 20231003081927_add_user_previous_email.exs + - 20231010074900_add_unique_index_on_site_memberships_site_id_when_owner.exs + - 20231011101825_add_email_activation_codes.exs + - 20231018081657_add_last_used_at_to_plugins_api_tokens.exs + - 20231109090334_add_site_user_preferences.exs + - 20231115131025_add_limits_to_enterprise_plans.exs + - 20231115140646_add_totp_user_fields_and_recovery_codes.exs + - 20231121131602_create_plans_table.exs + - 20231127132321_remove_custom_domains.exs + - 20231129103158_add_allow_next_upgrade_override_to_users.exs + - 20231129161022_add_totp_token_to_users.exs + - 20231204151831_backfill_last_bill_date_to_subscriptions.exs + - 20231208125624_add_data_retention_in_years_to_plans.exs + - 20231211092344_add_accept_traffic_until_to_sites.exs + - 20231219083050_track_accept_traffic_until_notifcations.exs + - 20231220072829_add_accept_traffic_until_to_user.exs + - 20231220101920_backfill_accept_traffic_until.exs + - 20240103090304_upgrade_oban_jobs_to_v12.exs + - 20240123085318_add_ip_block_list_table.exs + - 20240123095646_remove_google_analytics_imports_jobs.exs + - 20240123144308_add_site_imports.exs + - 20240129102900_migrate_accepted_traffic_until.exs + - 20240129113531_backfill_accept_traffic_until_for_users_missing_notifications.exs + - 20240214114158_add_legacy_flag_to_site_imports.exs + - 20240220144655_cascade_delete_ip_rules.exs + - 20240221122626_shield_country_rules.exs + - 20240307083402_shield_page_rules.exs + - 20240319094940_add_label_to_site_imports.exs + - 20240407104659_shield_hostname_rules.exs + - 20240528115149_migrate_site_imports.exs + - 20240702055817_traffic_drop_notifications.exs + - 20240708120453_create_help_scout_credentials.exs + - 20240722143005_create_helpscout_mappings.exs + - 20240801052902_add_goal_display_name.exs + - 20240801052903_make_goal_display_names_unique.exs + - 20240809100853_turn_google_auth_tokens_into_text.exs + + priv/ingest_repo/migrations/ + - 20231017073642_disable_deduplication_window_for_imports.exs + - 20240123142959_add_import_id_to_imported_tables.exs + - 20240209085338_minmax_index_session_timestamp.exs + - 20240220123656_create_sessions_events_compression_options.exs + - 20240222082911_sessions_v2_versioned_collapsing_merge_tree.exs + - 20240305085310_events_sessions_columns_improved.exs + - 20240326134840_add_metrics_to_imported_tables.exs + - 20240327085855_hostnames_in_sessions.exs + - 20240419133926_add_active_visitors_to_imported_pages.exs + - 20240423094014_add_imported_custom_events.exs + - 20240502115822_alias_api_prop_names.exs + - 20240709181437_populate_location_data.exs + + The migrations would happen in the following order: + + priv/repo/migrations/ + - 20230530161856_add_enable_feature_fields_for_site.exs + - 20230724131709_change_allowed_event_props_type.exs + - 20230802081520_cascade_delete_user.exs + - 20230914071244_fix_broken_goals.exs + - 20230914071245_goals_unique.exs + - 20230925072840_plugins_api_tokens.exs + - 20231003081927_add_user_previous_email.exs + - 20231010074900_add_unique_index_on_site_memberships_site_id_when_owner.exs + - 20231011101825_add_email_activation_codes.exs + + priv/ingest_repo/migrations/ + - 20231017073642_disable_deduplication_window_for_imports.exs + + priv/repo/migrations/ + - 20231018081657_add_last_used_at_to_plugins_api_tokens.exs + - 20231109090334_add_site_user_preferences.exs + - 20231115131025_add_limits_to_enterprise_plans.exs + - 20231115140646_add_totp_user_fields_and_recovery_codes.exs + - 20231121131602_create_plans_table.exs + - 20231127132321_remove_custom_domains.exs + - 20231129103158_add_allow_next_upgrade_override_to_users.exs + - 20231129161022_add_totp_token_to_users.exs + - 20231204151831_backfill_last_bill_date_to_subscriptions.exs + - 20231208125624_add_data_retention_in_years_to_plans.exs + - 20231211092344_add_accept_traffic_until_to_sites.exs + - 20231219083050_track_accept_traffic_until_notifcations.exs + - 20231220072829_add_accept_traffic_until_to_user.exs + - 20231220101920_backfill_accept_traffic_until.exs + - 20240103090304_upgrade_oban_jobs_to_v12.exs + - 20240123085318_add_ip_block_list_table.exs + - 20240123095646_remove_google_analytics_imports_jobs.exs + + priv/ingest_repo/migrations/ + - 20240123142959_add_import_id_to_imported_tables.exs + + priv/repo/migrations/ + - 20240123144308_add_site_imports.exs + - 20240129102900_migrate_accepted_traffic_until.exs + - 20240129113531_backfill_accept_traffic_until_for_users_missing_notifications.exs + + priv/ingest_repo/migrations/ + - 20240209085338_minmax_index_session_timestamp.exs + + priv/repo/migrations/ + - 20240214114158_add_legacy_flag_to_site_imports.exs + + priv/ingest_repo/migrations/ + - 20240220123656_create_sessions_events_compression_options.exs + + priv/repo/migrations/ + - 20240220144655_cascade_delete_ip_rules.exs + - 20240221122626_shield_country_rules.exs + + priv/ingest_repo/migrations/ + - 20240222082911_sessions_v2_versioned_collapsing_merge_tree.exs + - 20240305085310_events_sessions_columns_improved.exs + + priv/repo/migrations/ + - 20240307083402_shield_page_rules.exs + - 20240319094940_add_label_to_site_imports.exs + + priv/ingest_repo/migrations/ + - 20240326134840_add_metrics_to_imported_tables.exs + - 20240327085855_hostnames_in_sessions.exs + + priv/repo/migrations/ + - 20240407104659_shield_hostname_rules.exs + + priv/ingest_repo/migrations/ + - 20240419133926_add_active_visitors_to_imported_pages.exs + - 20240423094014_add_imported_custom_events.exs + - 20240502115822_alias_api_prop_names.exs + + priv/repo/migrations/ + - 20240528115149_migrate_site_imports.exs + - 20240702055817_traffic_drop_notifications.exs + - 20240708120453_create_help_scout_credentials.exs + + priv/ingest_repo/migrations/ + - 20240709181437_populate_location_data.exs + + priv/repo/migrations/ + - 20240722143005_create_helpscout_mappings.exs + - 20240801052902_add_goal_display_name.exs + - 20240801052903_make_goal_display_names_unique.exs + - 20240809100853_turn_google_auth_tokens_into_text.exs + + This approach helps resolve dependencies between migrations across repos. + """ + def interweave_migrate do # interweave all_pending = Enum.flat_map(repos(), fn repo -> @@ -42,29 +194,30 @@ defmodule Plausible.Release do end) # sort - all_sorted = - Enum.sort_by(all_pending, fn {_repo, version} -> version end, :asc) + all_sorted = Enum.sort_by(all_pending, fn {_repo, version} -> version end, :asc) # group into streaks streaks = migration_streaks(all_sorted) - # migrate + # migrate the streaks Enum.each(streaks, fn {repo, version} -> {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, to: version)) end) end @doc false - defp migration_streaks([{repo, version} | streaks]) do + def migration_streaks([{repo, version} | streaks]) do migration_streaks(streaks, repo, version) end - defp migration_streaks([] = empty), do: empty + def migration_streaks([] = empty), do: empty + # extend the streak defp migration_streaks([{repo, version} | rest], repo, _prev_version) do migration_streaks(rest, repo, version) end + # end the streak defp migration_streaks([{repo, version} | rest], prev_repo, prev_version) do [{prev_repo, prev_version} | migration_streaks(rest, repo, version)] end From 26eb9189663f1d29e2acde7bade46b7e2d21104c Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Mon, 26 Aug 2024 12:23:19 +0700 Subject: [PATCH 05/20] tests --- lib/plausible_release.ex | 225 ++++++-------------------------- rel/overlays/migrate.sh | 2 +- test/plausible/release_test.exs | 196 ++++++++++++++++++++++++++++ test/test_helper.exs | 6 +- 4 files changed, 239 insertions(+), 190 deletions(-) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index 6617dadf1f07..fdee395230a3 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -25,204 +25,55 @@ defmodule Plausible.Release do IO.puts("Migrations successful!") end - @doc """ - Unlike `migrate/0` above this function: - - lists all pending migrations across repos, - - sorts them into a single list, - - groups consequent migration into "streaks" by repo, - - migrates each repo in "streak" consequently - - For examples, assuming wi have the following migrations across two repos: - - priv/repo/migrations/ - - 20230530161856_add_enable_feature_fields_for_site.exs - - 20230724131709_change_allowed_event_props_type.exs - - 20230802081520_cascade_delete_user.exs - - 20230914071244_fix_broken_goals.exs - - 20230914071245_goals_unique.exs - - 20230925072840_plugins_api_tokens.exs - - 20231003081927_add_user_previous_email.exs - - 20231010074900_add_unique_index_on_site_memberships_site_id_when_owner.exs - - 20231011101825_add_email_activation_codes.exs - - 20231018081657_add_last_used_at_to_plugins_api_tokens.exs - - 20231109090334_add_site_user_preferences.exs - - 20231115131025_add_limits_to_enterprise_plans.exs - - 20231115140646_add_totp_user_fields_and_recovery_codes.exs - - 20231121131602_create_plans_table.exs - - 20231127132321_remove_custom_domains.exs - - 20231129103158_add_allow_next_upgrade_override_to_users.exs - - 20231129161022_add_totp_token_to_users.exs - - 20231204151831_backfill_last_bill_date_to_subscriptions.exs - - 20231208125624_add_data_retention_in_years_to_plans.exs - - 20231211092344_add_accept_traffic_until_to_sites.exs - - 20231219083050_track_accept_traffic_until_notifcations.exs - - 20231220072829_add_accept_traffic_until_to_user.exs - - 20231220101920_backfill_accept_traffic_until.exs - - 20240103090304_upgrade_oban_jobs_to_v12.exs - - 20240123085318_add_ip_block_list_table.exs - - 20240123095646_remove_google_analytics_imports_jobs.exs - - 20240123144308_add_site_imports.exs - - 20240129102900_migrate_accepted_traffic_until.exs - - 20240129113531_backfill_accept_traffic_until_for_users_missing_notifications.exs - - 20240214114158_add_legacy_flag_to_site_imports.exs - - 20240220144655_cascade_delete_ip_rules.exs - - 20240221122626_shield_country_rules.exs - - 20240307083402_shield_page_rules.exs - - 20240319094940_add_label_to_site_imports.exs - - 20240407104659_shield_hostname_rules.exs - - 20240528115149_migrate_site_imports.exs - - 20240702055817_traffic_drop_notifications.exs - - 20240708120453_create_help_scout_credentials.exs - - 20240722143005_create_helpscout_mappings.exs - - 20240801052902_add_goal_display_name.exs - - 20240801052903_make_goal_display_names_unique.exs - - 20240809100853_turn_google_auth_tokens_into_text.exs - - priv/ingest_repo/migrations/ - - 20231017073642_disable_deduplication_window_for_imports.exs - - 20240123142959_add_import_id_to_imported_tables.exs - - 20240209085338_minmax_index_session_timestamp.exs - - 20240220123656_create_sessions_events_compression_options.exs - - 20240222082911_sessions_v2_versioned_collapsing_merge_tree.exs - - 20240305085310_events_sessions_columns_improved.exs - - 20240326134840_add_metrics_to_imported_tables.exs - - 20240327085855_hostnames_in_sessions.exs - - 20240419133926_add_active_visitors_to_imported_pages.exs - - 20240423094014_add_imported_custom_events.exs - - 20240502115822_alias_api_prop_names.exs - - 20240709181437_populate_location_data.exs - - The migrations would happen in the following order: - - priv/repo/migrations/ - - 20230530161856_add_enable_feature_fields_for_site.exs - - 20230724131709_change_allowed_event_props_type.exs - - 20230802081520_cascade_delete_user.exs - - 20230914071244_fix_broken_goals.exs - - 20230914071245_goals_unique.exs - - 20230925072840_plugins_api_tokens.exs - - 20231003081927_add_user_previous_email.exs - - 20231010074900_add_unique_index_on_site_memberships_site_id_when_owner.exs - - 20231011101825_add_email_activation_codes.exs - - priv/ingest_repo/migrations/ - - 20231017073642_disable_deduplication_window_for_imports.exs - - priv/repo/migrations/ - - 20231018081657_add_last_used_at_to_plugins_api_tokens.exs - - 20231109090334_add_site_user_preferences.exs - - 20231115131025_add_limits_to_enterprise_plans.exs - - 20231115140646_add_totp_user_fields_and_recovery_codes.exs - - 20231121131602_create_plans_table.exs - - 20231127132321_remove_custom_domains.exs - - 20231129103158_add_allow_next_upgrade_override_to_users.exs - - 20231129161022_add_totp_token_to_users.exs - - 20231204151831_backfill_last_bill_date_to_subscriptions.exs - - 20231208125624_add_data_retention_in_years_to_plans.exs - - 20231211092344_add_accept_traffic_until_to_sites.exs - - 20231219083050_track_accept_traffic_until_notifcations.exs - - 20231220072829_add_accept_traffic_until_to_user.exs - - 20231220101920_backfill_accept_traffic_until.exs - - 20240103090304_upgrade_oban_jobs_to_v12.exs - - 20240123085318_add_ip_block_list_table.exs - - 20240123095646_remove_google_analytics_imports_jobs.exs - - priv/ingest_repo/migrations/ - - 20240123142959_add_import_id_to_imported_tables.exs - - priv/repo/migrations/ - - 20240123144308_add_site_imports.exs - - 20240129102900_migrate_accepted_traffic_until.exs - - 20240129113531_backfill_accept_traffic_until_for_users_missing_notifications.exs - - priv/ingest_repo/migrations/ - - 20240209085338_minmax_index_session_timestamp.exs - - priv/repo/migrations/ - - 20240214114158_add_legacy_flag_to_site_imports.exs - - priv/ingest_repo/migrations/ - - 20240220123656_create_sessions_events_compression_options.exs - - priv/repo/migrations/ - - 20240220144655_cascade_delete_ip_rules.exs - - 20240221122626_shield_country_rules.exs - - priv/ingest_repo/migrations/ - - 20240222082911_sessions_v2_versioned_collapsing_merge_tree.exs - - 20240305085310_events_sessions_columns_improved.exs - - priv/repo/migrations/ - - 20240307083402_shield_page_rules.exs - - 20240319094940_add_label_to_site_imports.exs - - priv/ingest_repo/migrations/ - - 20240326134840_add_metrics_to_imported_tables.exs - - 20240327085855_hostnames_in_sessions.exs - - priv/repo/migrations/ - - 20240407104659_shield_hostname_rules.exs - - priv/ingest_repo/migrations/ - - 20240419133926_add_active_visitors_to_imported_pages.exs - - 20240423094014_add_imported_custom_events.exs - - 20240502115822_alias_api_prop_names.exs - - priv/repo/migrations/ - - 20240528115149_migrate_site_imports.exs - - 20240702055817_traffic_drop_notifications.exs - - 20240708120453_create_help_scout_credentials.exs - - priv/ingest_repo/migrations/ - - 20240709181437_populate_location_data.exs - - priv/repo/migrations/ - - 20240722143005_create_helpscout_mappings.exs - - 20240801052902_add_goal_display_name.exs - - 20240801052903_make_goal_display_names_unique.exs - - 20240809100853_turn_google_auth_tokens_into_text.exs - - This approach helps resolve dependencies between migrations across repos. - """ - def interweave_migrate do - # interweave - all_pending = - Enum.flat_map(repos(), fn repo -> - Ecto.Migrator.migrations(repo) - |> Enum.filter(fn {status, _version, _name} -> status == :down end) - |> Enum.map(fn {_status, version, _name} -> {repo, version} end) - end) - - # sort - all_sorted = Enum.sort_by(all_pending, fn {_repo, version} -> version end, :asc) + def interweave_migrate(repos \\ repos()) do + prepare() - # group into streaks - streaks = migration_streaks(all_sorted) + streaks = migration_streaks(repos) - # migrate the streaks - Enum.each(streaks, fn {repo, version} -> - {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, to: version)) + Enum.each(streaks, fn {repo, up_to_version} -> + {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, to: up_to_version)) end) + + IO.puts("Migrations successful!") end @doc false - def migration_streaks([{repo, version} | streaks]) do - migration_streaks(streaks, repo, version) - end - def migration_streaks([] = empty), do: empty + def migration_streaks(repos) do + all_pending = + Enum.flat_map(repos, fn repo -> + # credo:disable-for-lines:6 Credo.Check.Refactor.Nesting + {:ok, pending, _started} = + Ecto.Migrator.with_repo(repo, fn repo -> + Ecto.Migrator.migrations(repo) + |> Enum.filter(fn {status, _version, _name} -> status == :down end) + |> Enum.map(fn {_status, version, _name} -> {repo, version} end) + end) + + pending + end) - # extend the streak - defp migration_streaks([{repo, version} | rest], repo, _prev_version) do - migration_streaks(rest, repo, version) + group_migration_streaks(all_pending) end - # end the streak - defp migration_streaks([{repo, version} | rest], prev_repo, prev_version) do - [{prev_repo, prev_version} | migration_streaks(rest, repo, version)] - end + @doc false + def group_migration_streaks(all_pending) do + all_sorted = Enum.sort_by(all_pending, fn {_repo, version} -> version end, :asc) + + streaks_reversed = + Enum.reduce(all_sorted, [], fn {repo, _version} = latest_migration, streaks_acc -> + case streaks_acc do + # start the streak for repo + [] -> [latest_migration] + # extend the streak + [{^repo, _prev_version} | rest] -> [latest_migration | rest] + # end the streak for prev_repo, start the streak for repo + [{_prev_repo, _prev_version} | _rest] -> [latest_migration | streaks_acc] + end + end) - defp migration_streaks([], repo, version), do: [{repo, version}] + :lists.reverse(streaks_reversed) + end def pending_migrations do prepare() diff --git a/rel/overlays/migrate.sh b/rel/overlays/migrate.sh index 15a0e0d4061d..3da1c2fd9d4c 100755 --- a/rel/overlays/migrate.sh +++ b/rel/overlays/migrate.sh @@ -3,4 +3,4 @@ BIN_DIR=$(dirname "$0") -"${BIN_DIR}"/bin/plausible eval Plausible.Release.migrate +"${BIN_DIR}"/bin/plausible eval Plausible.Release.interweave_migrate diff --git a/test/plausible/release_test.exs b/test/plausible/release_test.exs index 4d35bdab292d..dd62d2e7ce88 100644 --- a/test/plausible/release_test.exs +++ b/test/plausible/release_test.exs @@ -40,4 +40,200 @@ defmodule Plausible.ReleaseTest do assert stdout =~ "Starting repos.." assert stdout =~ "Inserted 54 plans" end + + test "ecto_repos sanity check" do + # if the repos here are modified, please make sure `interweave_migrate/0` is properly updated as well + assert Application.get_env(:plausible, :ecto_repos) == [Plausible.Repo, Plausible.IngestRepo] + end + + # these tests create new pg and ch databases (plausible_test_migrations), + # run various migrations between released versions (e.g. v2.0.0 -> v2.1.0-rc.0 -> ... -> master) + # and then drop it in the end. + # + # since completely separate databases are used, these tests are safe to run async + describe "interweave_migrate/0" do + # @describetag :slow + + # this repo is used in place of Plausible.Repo + defmodule PostgreSQL do + use Ecto.Repo, otp_app: :plausible, adapter: Ecto.Adapters.Postgres + end + + # this repo is used in place of Plausible.IngestRepo + defmodule ClickHouse do + use Ecto.Repo, otp_app: :plausible, adapter: Ecto.Adapters.ClickHouse + end + + setup do + pg_config = + Plausible.Repo.config() + |> Keyword.replace!(:database, "plausible_test_migrations") + |> Keyword.put(:priv, "priv/repo") + + ch_config = + Plausible.IngestRepo.config() + |> Keyword.replace!(:database, "plausible_test_migrations") + |> Keyword.put(:priv, "priv/ingest_repo") + + Application.put_env(:plausible, PostgreSQL, pg_config) + on_exit(fn -> Application.delete_env(:plausible, PostgreSQL) end) + + Application.put_env(:plausible, ClickHouse, ch_config) + on_exit(fn -> Application.delete_env(:plausible, ClickHouse) end) + + :ok = PostgreSQL.__adapter__().storage_up(PostgreSQL.config()) + on_exit(fn -> :ok = PostgreSQL.__adapter__().storage_down(PostgreSQL.config()) end) + + :ok = ClickHouse.__adapter__().storage_up(ClickHouse.config()) + on_exit(fn -> :ok = ClickHouse.__adapter__().storage_down(ClickHouse.config()) end) + + :ok + end + + test "v2.0.0 -> master" do + # + # migrate to v2.0.0 + # + + # https://github.com/plausible/analytics/tree/v2.0.0/priv/repo/migrations + {last_v200_pg_migration, _} = + Integer.parse("20230516131041_add_unique_index_to_api_keys.exs") + + # https://github.com/plausible/analytics/tree/v2.0.0/priv/ingest_repo/migrations + {last_v200_ch_migration, _} = + Integer.parse("20230509124919_clean_up_old_tables_after_v2_migration.exs") + + Ecto.Migrator.with_repo(PostgreSQL, &Ecto.Migrator.run(&1, :up, to: last_v200_pg_migration)) + Ecto.Migrator.with_repo(ClickHouse, &Ecto.Migrator.run(&1, :up, to: last_v200_ch_migration)) + + # + # insert some data into the tables (similar to seeds) + # + + # TODO + # PostgreSQL.insert!() + # ClickHouse.insert!() + + # + # sanity-check pending migrations + # + + all_pending = + Enum.flat_map([PostgreSQL, ClickHouse], fn repo -> + {:ok, pending, _started} = + Ecto.Migrator.with_repo(repo, fn repo -> + Ecto.Migrator.migrations(repo) + |> Enum.filter(fn {status, _version, _name} -> status == :down end) + |> Enum.map(fn {_status, version, name} -> {repo, version, name} end) + end) + + pending + end) + + all_sorted = Enum.sort_by(all_pending, fn {_repo, version, _name} -> version end, :asc) + + assert [ + {PostgreSQL, 20_230_530_161_856, "add_enable_feature_fields_for_site"}, + {PostgreSQL, 20_230_724_131_709, "change_allowed_event_props_type"}, + {PostgreSQL, 20_230_802_081_520, "cascade_delete_user"}, + {PostgreSQL, 20_230_914_071_244, "fix_broken_goals"}, + {PostgreSQL, 20_230_914_071_245, "goals_unique"}, + {PostgreSQL, 20_230_925_072_840, "plugins_api_tokens"}, + {PostgreSQL, 20_231_003_081_927, "add_user_previous_email"}, + {PostgreSQL, 20_231_010_074_900, + "add_unique_index_on_site_memberships_site_id_when_owner"}, + {PostgreSQL, 20_231_011_101_825, "add_email_activation_codes"}, + {ClickHouse, 20_231_017_073_642, "disable_deduplication_window_for_imports"}, + {PostgreSQL, 20_231_018_081_657, "add_last_used_at_to_plugins_api_tokens"}, + {PostgreSQL, 20_231_109_090_334, "add_site_user_preferences"}, + {PostgreSQL, 20_231_115_131_025, "add_limits_to_enterprise_plans"}, + {PostgreSQL, 20_231_115_140_646, "add_totp_user_fields_and_recovery_codes"}, + {PostgreSQL, 20_231_121_131_602, "create_plans_table"}, + {PostgreSQL, 20_231_127_132_321, "remove_custom_domains"}, + {PostgreSQL, 20_231_129_103_158, "add_allow_next_upgrade_override_to_users"}, + {PostgreSQL, 20_231_129_161_022, "add_totp_token_to_users"}, + {PostgreSQL, 20_231_204_151_831, "backfill_last_bill_date_to_subscriptions"}, + {PostgreSQL, 20_231_208_125_624, "add_data_retention_in_years_to_plans"}, + {PostgreSQL, 20_231_211_092_344, "add_accept_traffic_until_to_sites"}, + {PostgreSQL, 20_231_219_083_050, "track_accept_traffic_until_notifcations"}, + {PostgreSQL, 20_231_220_072_829, "add_accept_traffic_until_to_user"}, + {PostgreSQL, 20_231_220_101_920, "backfill_accept_traffic_until"}, + {PostgreSQL, 20_240_103_090_304, "upgrade_oban_jobs_to_v12"}, + {PostgreSQL, 20_240_123_085_318, "add_ip_block_list_table"}, + {PostgreSQL, 20_240_123_095_646, "remove_google_analytics_imports_jobs"}, + {ClickHouse, 20_240_123_142_959, "add_import_id_to_imported_tables"}, + {PostgreSQL, 20_240_123_144_308, "add_site_imports"}, + {PostgreSQL, 20_240_129_102_900, "migrate_accepted_traffic_until"}, + {PostgreSQL, 20_240_129_113_531, + "backfill_accept_traffic_until_for_users_missing_notifications"}, + {ClickHouse, 20_240_209_085_338, "minmax_index_session_timestamp"}, + {PostgreSQL, 20_240_214_114_158, "add_legacy_flag_to_site_imports"}, + {ClickHouse, 20_240_220_123_656, "create_sessions_events_compression_options"}, + {PostgreSQL, 20_240_220_144_655, "cascade_delete_ip_rules"}, + # v2.1.0-rc.0 is released here, cascade_delete_ip_rules is the last migration: + # https://github.com/plausible/analytics/tree/v2.1.0-rc.0/priv/repo/migrations + {PostgreSQL, 20_240_221_122_626, "shield_country_rules"}, + {ClickHouse, 20_240_222_082_911, "sessions_v2_versioned_collapsing_merge_tree"}, + {ClickHouse, 20_240_305_085_310, "events_sessions_columns_improved"}, + {PostgreSQL, 20_240_307_083_402, "shield_page_rules"}, + {PostgreSQL, 20_240_319_094_940, "add_label_to_site_imports"}, + {ClickHouse, 20_240_326_134_840, "add_metrics_to_imported_tables"}, + {ClickHouse, 20_240_327_085_855, "hostnames_in_sessions"}, + {PostgreSQL, 20_240_407_104_659, "shield_hostname_rules"}, + {ClickHouse, 20_240_419_133_926, "add_active_visitors_to_imported_pages"}, + {ClickHouse, 20_240_423_094_014, "add_imported_custom_events"}, + {ClickHouse, 20_240_502_115_822, "alias_api_prop_names"}, + # v2.1.0-rc.1 and v2.1.0 are released here, alias_api_prop_names is the last migration: + # https://github.com/plausible/analytics/tree/v2.1.0-rc.1/priv/ingest_repo/migrations + # https://github.com/plausible/analytics/tree/v2.1.0/priv/ingest_repo/migrations + {PostgreSQL, 20_240_528_115_149, "migrate_site_imports"} + # v2.1.1 is released here, migrate_site_imports is the last migration: + # https://github.com/plausible/analytics/tree/v2.1.1/priv/repo/migrations + + # unreleased + # {PostgreSQL, 20_240_702_055_817, "traffic_drop_notifications"}, + # {PostgreSQL, 20_240_708_120_453, "create_help_scout_credentials"}, + # {ClickHouse, 20_240_709_181_437, "populate_location_data"}, + # {PostgreSQL, 20_240_722_143_005, "create_helpscout_mappings"}, + # {PostgreSQL, 20_240_801_052_902, "add_goal_display_name"}, + # {PostgreSQL, 20_240_801_052_903, "make_goal_display_names_unique"}, + # {PostgreSQL, 20_240_809_100_853, "turn_google_auth_tokens_into_text"} + + | _future + ] = all_sorted + + # + # sanity-check pending "migration streaks" + # + + assert [ + {PostgreSQL, 20_231_011_101_825}, + {ClickHouse, 20_231_017_073_642}, + {PostgreSQL, 20_240_123_095_646}, + {ClickHouse, 20_240_123_142_959}, + {PostgreSQL, 20_240_129_113_531}, + {ClickHouse, 20_240_209_085_338}, + {PostgreSQL, 20_240_214_114_158}, + {ClickHouse, 20_240_220_123_656}, + {PostgreSQL, 20_240_221_122_626}, + {ClickHouse, 20_240_305_085_310}, + {PostgreSQL, 20_240_319_094_940}, + {ClickHouse, 20_240_327_085_855}, + {PostgreSQL, 20_240_407_104_659}, + {ClickHouse, 20_240_502_115_822}, + {PostgreSQL, 20_240_708_120_453} + + # {ClickHouse, 20_240_709_181_437} + # {PostgreSQL, 20_240_809_100_853} + + | _future + ] = Release.migration_streaks([PostgreSQL, ClickHouse]) + + # + # migrate all the way up to to master + # + + Release.interweave_migrate([PostgreSQL, ClickHouse]) + end + end end diff --git a/test/test_helper.exs b/test/test_helper.exs index d4bef1539538..28b49029a39e 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -20,10 +20,12 @@ if :minio in Keyword.fetch!(ExUnit.configuration(), :include) do Plausible.TestUtils.ensure_minio() end +default_exclude = [:slow, :minio, :migrations] + if Mix.env() == :ce_test do IO.puts("Test mode: Community Edition") - ExUnit.configure(exclude: [:slow, :minio, :ee_only]) + ExUnit.configure(exclude: [:ee_only | default_exclude]) else IO.puts("Test mode: Enterprise Edition") - ExUnit.configure(exclude: [:slow, :minio, :ce_build_only]) + ExUnit.configure(exclude: [:ce_build_only | default_exclude]) end From 3db1779f33aeb2a4621bb22bb5ce419749d0f68e Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:19:05 +0700 Subject: [PATCH 06/20] add comment --- lib/plausible_release.ex | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index fdee395230a3..d179356bed51 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -25,6 +25,11 @@ defmodule Plausible.Release do IO.puts("Migrations successful!") end + # Unlike `migrate/0` above this function: + # - lists all pending migrations across repos, + # - sorts them into a single list, + # - groups consequent migration into "streaks" by repo, + # - and migrates the repos through each streak def interweave_migrate(repos \\ repos()) do prepare() @@ -38,7 +43,6 @@ defmodule Plausible.Release do end @doc false - def migration_streaks(repos) do all_pending = Enum.flat_map(repos, fn repo -> @@ -53,12 +57,8 @@ defmodule Plausible.Release do pending end) - group_migration_streaks(all_pending) - end - - @doc false - def group_migration_streaks(all_pending) do - all_sorted = Enum.sort_by(all_pending, fn {_repo, version} -> version end, :asc) + all_sorted = + Enum.sort_by(all_pending, fn {_repo, version} -> version end, :asc) streaks_reversed = Enum.reduce(all_sorted, [], fn {repo, _version} = latest_migration, streaks_acc -> From c49293710e1e816ae7e5fd651f97579a5bb409f7 Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:22:04 +0700 Subject: [PATCH 07/20] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0af8054c5d60..e6287abac4aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ All notable changes to this project will be documented in this file. - Don't include imports when showing time series hourly interval. Previously imported data was shown each midnight - Fix property filter suggestions 500 error when property hasn't been selected - Bamboo.Mua: add Date and Message-ID headers if missing plausible/analytics#4474 +- Fix migration order across `plausible_db` and `plausible_events_db` databases plausible/analytics#4466 ## v2.1.1 - 2024-06-06 From 6a26b81477a4e476e7ee5ff915aefd2f4baa199a Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:30:45 +0700 Subject: [PATCH 08/20] continue --- lib/plausible_release.ex | 2 -- test/plausible/release_test.exs | 21 +++++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index d179356bed51..c097afae4f33 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -38,8 +38,6 @@ defmodule Plausible.Release do Enum.each(streaks, fn {repo, up_to_version} -> {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, to: up_to_version)) end) - - IO.puts("Migrations successful!") end @doc false diff --git a/test/plausible/release_test.exs b/test/plausible/release_test.exs index dd62d2e7ce88..89d3d6ca1fca 100644 --- a/test/plausible/release_test.exs +++ b/test/plausible/release_test.exs @@ -42,17 +42,17 @@ defmodule Plausible.ReleaseTest do end test "ecto_repos sanity check" do - # if the repos here are modified, please make sure `interweave_migrate/0` is properly updated as well + # if the repos here are modified, please make sure `interweave_migrate/0` tests below are properly updated as well assert Application.get_env(:plausible, :ecto_repos) == [Plausible.Repo, Plausible.IngestRepo] end - # these tests create new pg and ch databases (plausible_test_migrations), + # these tests create new pg and ch databases (named plausible_test_migrations), # run various migrations between released versions (e.g. v2.0.0 -> v2.1.0-rc.0 -> ... -> master) - # and then drop it in the end. + # and then drop them in the end. # # since completely separate databases are used, these tests are safe to run async describe "interweave_migrate/0" do - # @describetag :slow + @describetag :migrations # this repo is used in place of Plausible.Repo defmodule PostgreSQL do @@ -68,11 +68,13 @@ defmodule Plausible.ReleaseTest do pg_config = Plausible.Repo.config() |> Keyword.replace!(:database, "plausible_test_migrations") + # to see priv/repo/migrations from this fake pg repo |> Keyword.put(:priv, "priv/repo") ch_config = Plausible.IngestRepo.config() |> Keyword.replace!(:database, "plausible_test_migrations") + # to see priv/ingest_repo/migrations from this fake ch repo |> Keyword.put(:priv, "priv/ingest_repo") Application.put_env(:plausible, PostgreSQL, pg_config) @@ -81,11 +83,13 @@ defmodule Plausible.ReleaseTest do Application.put_env(:plausible, ClickHouse, ch_config) on_exit(fn -> Application.delete_env(:plausible, ClickHouse) end) - :ok = PostgreSQL.__adapter__().storage_up(PostgreSQL.config()) - on_exit(fn -> :ok = PostgreSQL.__adapter__().storage_down(PostgreSQL.config()) end) + pg_config = PostgreSQL.config() + :ok = Ecto.Adapters.Postgres.storage_up(pg_config) + on_exit(fn -> :ok = Ecto.Adapters.Postgres.storage_down(pg_config) end) - :ok = ClickHouse.__adapter__().storage_up(ClickHouse.config()) - on_exit(fn -> :ok = ClickHouse.__adapter__().storage_down(ClickHouse.config()) end) + ch_config = ClickHouse.config() + :ok = Ecto.Adapters.ClickHouse.storage_up(ch_config) + on_exit(fn -> :ok = Ecto.Adapters.ClickHouse.storage_down(ch_config) end) :ok end @@ -223,6 +227,7 @@ defmodule Plausible.ReleaseTest do {ClickHouse, 20_240_502_115_822}, {PostgreSQL, 20_240_708_120_453} + # unreleased # {ClickHouse, 20_240_709_181_437} # {PostgreSQL, 20_240_809_100_853} From cc7ba1fa1ef4a30bfa04599cb01d1203d900976d Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:34:14 +0700 Subject: [PATCH 09/20] run migrations tests in ci --- .github/workflows/elixir.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index 376b22e62c47..9f24459b93fb 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -108,12 +108,12 @@ jobs: - run: make minio if: env.MIX_ENV == 'test' - - run: mix test --include slow --include minio --max-failures 1 --warnings-as-errors + - run: mix test --include slow --include minio --include migrations --max-failures 1 --warnings-as-errors if: env.MIX_ENV == 'test' env: MINIO_HOST_FOR_CLICKHOUSE: "172.17.0.1" - - run: mix test --include slow --max-failures 1 --warnings-as-errors + - run: mix test --include slow --include migrations --max-failures 1 --warnings-as-errors if: env.MIX_ENV == 'ce_test' static: From 7922473180928f30fea818d63b7240b030ba068f Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Fri, 30 Aug 2024 09:40:40 +0700 Subject: [PATCH 10/20] add pending_streams cmd --- lib/plausible_release.ex | 40 ++++++++++++ rel/overlays/pending-migrations.sh | 2 +- test/plausible/release_test.exs | 100 ++++++++++++++++++++++++++++- 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index c097afae4f33..fac321abb209 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -80,6 +80,46 @@ defmodule Plausible.Release do Enum.each(repos(), &list_pending_migrations_for/1) end + def pending_streaks(repos \\ repos()) do + prepare() + IO.puts("Collecting pending migrations..\n") + + streaks = migration_streaks(repos) + + all_pending = + Enum.flat_map(repos, fn repo -> + # credo:disable-for-lines:6 Credo.Check.Refactor.Nesting + {:ok, pending, _started} = + Ecto.Migrator.with_repo(repo, fn repo -> + Ecto.Migrator.migrations(repo) + |> Enum.filter(fn {status, _version, _name} -> status == :down end) + |> Enum.map(fn {_status, version, name} -> {repo, version, name} end) + end) + + pending + end) + + print_streaks(streaks, all_pending) + end + + defp print_streaks([{repo, up_to_version} | streaks], pending) do + {streak, pending} = + Enum.split_with(pending, fn {pending_repo, version, _name} -> + pending_repo == repo and version <= up_to_version + end) + + IO.puts( + "#{inspect(repo)} [#{Path.relative_to_cwd(Ecto.Migrator.migrations_path(repo))}] streak up to version #{up_to_version}:" + ) + + Enum.each(streak, fn {_repo, version, name} -> IO.puts(" * #{version}_#{name}") end) + IO.puts("") + + print_streaks(streaks, pending) + end + + defp print_streaks([], []), do: :ok + def seed do prepare() # Run seed script diff --git a/rel/overlays/pending-migrations.sh b/rel/overlays/pending-migrations.sh index 12b2ce9e0dbd..8b018e84a9e0 100755 --- a/rel/overlays/pending-migrations.sh +++ b/rel/overlays/pending-migrations.sh @@ -3,4 +3,4 @@ BIN_DIR=$(dirname "$0") -"${BIN_DIR}"/bin/plausible eval Plausible.Release.pending_migrations +"${BIN_DIR}"/bin/plausible eval Plausible.Release.pending_streaks diff --git a/test/plausible/release_test.exs b/test/plausible/release_test.exs index 89d3d6ca1fca..f83bf1de6de3 100644 --- a/test/plausible/release_test.exs +++ b/test/plausible/release_test.exs @@ -234,11 +234,107 @@ defmodule Plausible.ReleaseTest do | _future ] = Release.migration_streaks([PostgreSQL, ClickHouse]) + assert """ + Loading plausible.. + Starting dependencies.. + Starting repos.. + Collecting pending migrations.. + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20231011101825: + * 20230530161856_add_enable_feature_fields_for_site + * 20230724131709_change_allowed_event_props_type + * 20230802081520_cascade_delete_user + * 20230914071244_fix_broken_goals + * 20230914071245_goals_unique + * 20230925072840_plugins_api_tokens + * 20231003081927_add_user_previous_email + * 20231010074900_add_unique_index_on_site_memberships_site_id_when_owner + * 20231011101825_add_email_activation_codes + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20231017073642: + * 20231017073642_disable_deduplication_window_for_imports + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20240123095646: + * 20231018081657_add_last_used_at_to_plugins_api_tokens + * 20231109090334_add_site_user_preferences + * 20231115131025_add_limits_to_enterprise_plans + * 20231115140646_add_totp_user_fields_and_recovery_codes + * 20231121131602_create_plans_table + * 20231127132321_remove_custom_domains + * 20231129103158_add_allow_next_upgrade_override_to_users + * 20231129161022_add_totp_token_to_users + * 20231204151831_backfill_last_bill_date_to_subscriptions + * 20231208125624_add_data_retention_in_years_to_plans + * 20231211092344_add_accept_traffic_until_to_sites + * 20231219083050_track_accept_traffic_until_notifcations + * 20231220072829_add_accept_traffic_until_to_user + * 20231220101920_backfill_accept_traffic_until + * 20240103090304_upgrade_oban_jobs_to_v12 + * 20240123085318_add_ip_block_list_table + * 20240123095646_remove_google_analytics_imports_jobs + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20240123142959: + * 20240123142959_add_import_id_to_imported_tables + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20240129113531: + * 20240123144308_add_site_imports + * 20240129102900_migrate_accepted_traffic_until + * 20240129113531_backfill_accept_traffic_until_for_users_missing_notifications + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20240209085338: + * 20240209085338_minmax_index_session_timestamp + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20240214114158: + * 20240214114158_add_legacy_flag_to_site_imports + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20240220123656: + * 20240220123656_create_sessions_events_compression_options + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20240221122626: + * 20240220144655_cascade_delete_ip_rules + * 20240221122626_shield_country_rules + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20240305085310: + * 20240222082911_sessions_v2_versioned_collapsing_merge_tree + * 20240305085310_events_sessions_columns_improved + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20240319094940: + * 20240307083402_shield_page_rules + * 20240319094940_add_label_to_site_imports + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20240327085855: + * 20240326134840_add_metrics_to_imported_tables + * 20240327085855_hostnames_in_sessions + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20240407104659: + * 20240407104659_shield_hostname_rules + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20240502115822: + * 20240419133926_add_active_visitors_to_imported_pages + * 20240423094014_add_imported_custom_events + * 20240502115822_alias_api_prop_names + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20240708120453: + * 20240528115149_migrate_site_imports + * 20240702055817_traffic_drop_notifications + * 20240708120453_create_help_scout_credentials + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20240709181437: + * 20240709181437_populate_location_data + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20240809100853: + * 20240722143005_create_helpscout_mappings + * 20240801052902_add_goal_display_name + * 20240801052903_make_goal_display_names_unique + * 20240809100853_turn_google_auth_tokens_into_text + """ <> _future = + capture_io(fn -> Release.pending_streaks([PostgreSQL, ClickHouse]) end) + # - # migrate all the way up to to master + # and finally migrate all the way up to to master # - Release.interweave_migrate([PostgreSQL, ClickHouse]) + _logs = capture_io(fn -> Release.interweave_migrate([PostgreSQL, ClickHouse]) end) end end end From 534270890676e58b8e13b8fa23cc0ecadb158b13 Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Fri, 30 Aug 2024 09:48:17 +0700 Subject: [PATCH 11/20] fix ci --- test/plausible/release_test.exs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/plausible/release_test.exs b/test/plausible/release_test.exs index f83bf1de6de3..d973e2607d90 100644 --- a/test/plausible/release_test.exs +++ b/test/plausible/release_test.exs @@ -234,6 +234,16 @@ defmodule Plausible.ReleaseTest do | _future ] = Release.migration_streaks([PostgreSQL, ClickHouse]) + pending_streaks = capture_io(fn -> Release.pending_streaks([PostgreSQL, ClickHouse]) end) + + pending_streaks = + if Plausible.ce?() do + # just to make the tests pass in CI + String.replace(pending_streaks, "_build/ce_test/lib", "_build/test/lib") + else + pending_streaks + end + assert """ Loading plausible.. Starting dependencies.. @@ -327,8 +337,7 @@ defmodule Plausible.ReleaseTest do * 20240801052902_add_goal_display_name * 20240801052903_make_goal_display_names_unique * 20240809100853_turn_google_auth_tokens_into_text - """ <> _future = - capture_io(fn -> Release.pending_streaks([PostgreSQL, ClickHouse]) end) + """ <> _future = pending_streaks # # and finally migrate all the way up to to master From 15bcc8656b7c88df70ace746e5d26a8fbd3e871f Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Fri, 30 Aug 2024 09:59:59 +0700 Subject: [PATCH 12/20] add docs --- lib/plausible_release.ex | 42 +++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index fac321abb209..929f07fcacf4 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -25,11 +25,43 @@ defmodule Plausible.Release do IO.puts("Migrations successful!") end - # Unlike `migrate/0` above this function: - # - lists all pending migrations across repos, - # - sorts them into a single list, - # - groups consequent migration into "streaks" by repo, - # - and migrates the repos through each streak + @doc """ + `interweave_migrate/0` is a more advanced (compared to `migrate/0`) migration function that: + + - Lists all pending migrations across multiple repositories. + - Sorts these migrations into a single list. + - Groups consecutive migrations by repository into "streaks". + - Executes the migrations in the correct order by processing each streak sequentially. + + ### Why Use This Approach? + + This function resolves dependencies between migrations that span across different repositories. + The default `migrate/0` function migrates each repository independently, which may result in + migrations running in the wrong order when there are cross-repository dependencies. + + Consider the following example: + + - **Migration 1**: The PostgreSQL (PG) repository creates a table named `site_imports`. + - **Migration 2**: The ClickHouse (CH) repository creates `import_id` columns in `imported_*` tables. + - **Migration 3**: The PG repository runs a data migration that utilizes both PG and CH databases, + reading from the `import_id` column in `imported_*` tables. + + The default `migrate/0` would execute these migrations by repository, resulting in the following order: + + 1. Migration 1 (PG) + 2. Migration 3 (PG) + 3. Migration 2 (CH) + + This sequence would fail at Migration 3, as the `import_id` columns in the CH repository have not been created yet. + + `interweave_migrate/0` addresses this issue by consolidating all pending migrations into a single, ordered queue: + + 1. Migration 1 (PG) + 2. Migration 2 (CH) + 3. Migration 3 (PG) + + This ensures all dependencies are resolved in the correct order. + """ def interweave_migrate(repos \\ repos()) do prepare() From bd13352465de141ebb6c43007b2e4186709c1eab Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Fri, 30 Aug 2024 10:03:39 +0700 Subject: [PATCH 13/20] fix test --- test/plausible/release_test.exs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/plausible/release_test.exs b/test/plausible/release_test.exs index d973e2607d90..7fbee9d83063 100644 --- a/test/plausible/release_test.exs +++ b/test/plausible/release_test.exs @@ -332,11 +332,6 @@ defmodule Plausible.ReleaseTest do Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20240709181437: * 20240709181437_populate_location_data - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20240809100853: - * 20240722143005_create_helpscout_mappings - * 20240801052902_add_goal_display_name - * 20240801052903_make_goal_display_names_unique - * 20240809100853_turn_google_auth_tokens_into_text """ <> _future = pending_streaks # From 23729a59e67478a2c2abef688b62f4750c95ce6b Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Fri, 30 Aug 2024 11:09:41 +0700 Subject: [PATCH 14/20] simplify test --- lib/plausible_release.ex | 2 +- test/plausible/release_test.exs | 344 ++++++++++++++++++-------------- 2 files changed, 190 insertions(+), 156 deletions(-) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index 929f07fcacf4..99505b9efd08 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -39,7 +39,7 @@ defmodule Plausible.Release do The default `migrate/0` function migrates each repository independently, which may result in migrations running in the wrong order when there are cross-repository dependencies. - Consider the following example: + Consider the following example (adapted from reality, not 100% accurate): - **Migration 1**: The PostgreSQL (PG) repository creates a table named `site_imports`. - **Migration 2**: The ClickHouse (CH) repository creates `import_id` columns in `imported_*` tables. diff --git a/test/plausible/release_test.exs b/test/plausible/release_test.exs index 7fbee9d83063..8fbe8a4f3621 100644 --- a/test/plausible/release_test.exs +++ b/test/plausible/release_test.exs @@ -1,5 +1,5 @@ defmodule Plausible.ReleaseTest do - use Plausible.DataCase, async: true + use Plausible.DataCase, async: false alias Plausible.{Release, Auth} import ExUnit.CaptureIO @@ -46,12 +46,7 @@ defmodule Plausible.ReleaseTest do assert Application.get_env(:plausible, :ecto_repos) == [Plausible.Repo, Plausible.IngestRepo] end - # these tests create new pg and ch databases (named plausible_test_migrations), - # run various migrations between released versions (e.g. v2.0.0 -> v2.1.0-rc.0 -> ... -> master) - # and then drop them in the end. - # - # since completely separate databases are used, these tests are safe to run async - describe "interweave_migrate/0" do + describe "pending_streaks/1" do @describetag :migrations # this repo is used in place of Plausible.Repo @@ -69,13 +64,13 @@ defmodule Plausible.ReleaseTest do Plausible.Repo.config() |> Keyword.replace!(:database, "plausible_test_migrations") # to see priv/repo/migrations from this fake pg repo - |> Keyword.put(:priv, "priv/repo") + |> Keyword.put_new(:priv, "priv/repo") ch_config = Plausible.IngestRepo.config() |> Keyword.replace!(:database, "plausible_test_migrations") # to see priv/ingest_repo/migrations from this fake ch repo - |> Keyword.put(:priv, "priv/ingest_repo") + |> Keyword.put_new(:priv, "priv/ingest_repo") Application.put_env(:plausible, PostgreSQL, pg_config) on_exit(fn -> Application.delete_env(:plausible, PostgreSQL) end) @@ -94,146 +89,7 @@ defmodule Plausible.ReleaseTest do :ok end - test "v2.0.0 -> master" do - # - # migrate to v2.0.0 - # - - # https://github.com/plausible/analytics/tree/v2.0.0/priv/repo/migrations - {last_v200_pg_migration, _} = - Integer.parse("20230516131041_add_unique_index_to_api_keys.exs") - - # https://github.com/plausible/analytics/tree/v2.0.0/priv/ingest_repo/migrations - {last_v200_ch_migration, _} = - Integer.parse("20230509124919_clean_up_old_tables_after_v2_migration.exs") - - Ecto.Migrator.with_repo(PostgreSQL, &Ecto.Migrator.run(&1, :up, to: last_v200_pg_migration)) - Ecto.Migrator.with_repo(ClickHouse, &Ecto.Migrator.run(&1, :up, to: last_v200_ch_migration)) - - # - # insert some data into the tables (similar to seeds) - # - - # TODO - # PostgreSQL.insert!() - # ClickHouse.insert!() - - # - # sanity-check pending migrations - # - - all_pending = - Enum.flat_map([PostgreSQL, ClickHouse], fn repo -> - {:ok, pending, _started} = - Ecto.Migrator.with_repo(repo, fn repo -> - Ecto.Migrator.migrations(repo) - |> Enum.filter(fn {status, _version, _name} -> status == :down end) - |> Enum.map(fn {_status, version, name} -> {repo, version, name} end) - end) - - pending - end) - - all_sorted = Enum.sort_by(all_pending, fn {_repo, version, _name} -> version end, :asc) - - assert [ - {PostgreSQL, 20_230_530_161_856, "add_enable_feature_fields_for_site"}, - {PostgreSQL, 20_230_724_131_709, "change_allowed_event_props_type"}, - {PostgreSQL, 20_230_802_081_520, "cascade_delete_user"}, - {PostgreSQL, 20_230_914_071_244, "fix_broken_goals"}, - {PostgreSQL, 20_230_914_071_245, "goals_unique"}, - {PostgreSQL, 20_230_925_072_840, "plugins_api_tokens"}, - {PostgreSQL, 20_231_003_081_927, "add_user_previous_email"}, - {PostgreSQL, 20_231_010_074_900, - "add_unique_index_on_site_memberships_site_id_when_owner"}, - {PostgreSQL, 20_231_011_101_825, "add_email_activation_codes"}, - {ClickHouse, 20_231_017_073_642, "disable_deduplication_window_for_imports"}, - {PostgreSQL, 20_231_018_081_657, "add_last_used_at_to_plugins_api_tokens"}, - {PostgreSQL, 20_231_109_090_334, "add_site_user_preferences"}, - {PostgreSQL, 20_231_115_131_025, "add_limits_to_enterprise_plans"}, - {PostgreSQL, 20_231_115_140_646, "add_totp_user_fields_and_recovery_codes"}, - {PostgreSQL, 20_231_121_131_602, "create_plans_table"}, - {PostgreSQL, 20_231_127_132_321, "remove_custom_domains"}, - {PostgreSQL, 20_231_129_103_158, "add_allow_next_upgrade_override_to_users"}, - {PostgreSQL, 20_231_129_161_022, "add_totp_token_to_users"}, - {PostgreSQL, 20_231_204_151_831, "backfill_last_bill_date_to_subscriptions"}, - {PostgreSQL, 20_231_208_125_624, "add_data_retention_in_years_to_plans"}, - {PostgreSQL, 20_231_211_092_344, "add_accept_traffic_until_to_sites"}, - {PostgreSQL, 20_231_219_083_050, "track_accept_traffic_until_notifcations"}, - {PostgreSQL, 20_231_220_072_829, "add_accept_traffic_until_to_user"}, - {PostgreSQL, 20_231_220_101_920, "backfill_accept_traffic_until"}, - {PostgreSQL, 20_240_103_090_304, "upgrade_oban_jobs_to_v12"}, - {PostgreSQL, 20_240_123_085_318, "add_ip_block_list_table"}, - {PostgreSQL, 20_240_123_095_646, "remove_google_analytics_imports_jobs"}, - {ClickHouse, 20_240_123_142_959, "add_import_id_to_imported_tables"}, - {PostgreSQL, 20_240_123_144_308, "add_site_imports"}, - {PostgreSQL, 20_240_129_102_900, "migrate_accepted_traffic_until"}, - {PostgreSQL, 20_240_129_113_531, - "backfill_accept_traffic_until_for_users_missing_notifications"}, - {ClickHouse, 20_240_209_085_338, "minmax_index_session_timestamp"}, - {PostgreSQL, 20_240_214_114_158, "add_legacy_flag_to_site_imports"}, - {ClickHouse, 20_240_220_123_656, "create_sessions_events_compression_options"}, - {PostgreSQL, 20_240_220_144_655, "cascade_delete_ip_rules"}, - # v2.1.0-rc.0 is released here, cascade_delete_ip_rules is the last migration: - # https://github.com/plausible/analytics/tree/v2.1.0-rc.0/priv/repo/migrations - {PostgreSQL, 20_240_221_122_626, "shield_country_rules"}, - {ClickHouse, 20_240_222_082_911, "sessions_v2_versioned_collapsing_merge_tree"}, - {ClickHouse, 20_240_305_085_310, "events_sessions_columns_improved"}, - {PostgreSQL, 20_240_307_083_402, "shield_page_rules"}, - {PostgreSQL, 20_240_319_094_940, "add_label_to_site_imports"}, - {ClickHouse, 20_240_326_134_840, "add_metrics_to_imported_tables"}, - {ClickHouse, 20_240_327_085_855, "hostnames_in_sessions"}, - {PostgreSQL, 20_240_407_104_659, "shield_hostname_rules"}, - {ClickHouse, 20_240_419_133_926, "add_active_visitors_to_imported_pages"}, - {ClickHouse, 20_240_423_094_014, "add_imported_custom_events"}, - {ClickHouse, 20_240_502_115_822, "alias_api_prop_names"}, - # v2.1.0-rc.1 and v2.1.0 are released here, alias_api_prop_names is the last migration: - # https://github.com/plausible/analytics/tree/v2.1.0-rc.1/priv/ingest_repo/migrations - # https://github.com/plausible/analytics/tree/v2.1.0/priv/ingest_repo/migrations - {PostgreSQL, 20_240_528_115_149, "migrate_site_imports"} - # v2.1.1 is released here, migrate_site_imports is the last migration: - # https://github.com/plausible/analytics/tree/v2.1.1/priv/repo/migrations - - # unreleased - # {PostgreSQL, 20_240_702_055_817, "traffic_drop_notifications"}, - # {PostgreSQL, 20_240_708_120_453, "create_help_scout_credentials"}, - # {ClickHouse, 20_240_709_181_437, "populate_location_data"}, - # {PostgreSQL, 20_240_722_143_005, "create_helpscout_mappings"}, - # {PostgreSQL, 20_240_801_052_902, "add_goal_display_name"}, - # {PostgreSQL, 20_240_801_052_903, "make_goal_display_names_unique"}, - # {PostgreSQL, 20_240_809_100_853, "turn_google_auth_tokens_into_text"} - - | _future - ] = all_sorted - - # - # sanity-check pending "migration streaks" - # - - assert [ - {PostgreSQL, 20_231_011_101_825}, - {ClickHouse, 20_231_017_073_642}, - {PostgreSQL, 20_240_123_095_646}, - {ClickHouse, 20_240_123_142_959}, - {PostgreSQL, 20_240_129_113_531}, - {ClickHouse, 20_240_209_085_338}, - {PostgreSQL, 20_240_214_114_158}, - {ClickHouse, 20_240_220_123_656}, - {PostgreSQL, 20_240_221_122_626}, - {ClickHouse, 20_240_305_085_310}, - {PostgreSQL, 20_240_319_094_940}, - {ClickHouse, 20_240_327_085_855}, - {PostgreSQL, 20_240_407_104_659}, - {ClickHouse, 20_240_502_115_822}, - {PostgreSQL, 20_240_708_120_453} - - # unreleased - # {ClickHouse, 20_240_709_181_437} - # {PostgreSQL, 20_240_809_100_853} - - | _future - ] = Release.migration_streaks([PostgreSQL, ClickHouse]) - + test "from scratch" do pending_streaks = capture_io(fn -> Release.pending_streaks([PostgreSQL, ClickHouse]) end) pending_streaks = @@ -250,7 +106,190 @@ defmodule Plausible.ReleaseTest do Starting repos.. Collecting pending migrations.. + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20200619071221: + * 20181201181549_add_pageviews + * 20181214201821_add_new_visitor_to_pageviews + * 20181215140923_add_session_id_to_pageviews + * 20190109173917_create_sites + * 20190117135714_add_uid_to_pageviews + * 20190118154210_add_derived_data_to_pageviews + * 20190126135857_add_name_to_users + * 20190127213938_add_tz_to_sites + * 20190205165931_add_last_seen_to_users + * 20190213224404_add_intro_emails + * 20190219130809_delete_intro_emails_when_user_is_deleted + * 20190301122344_add_country_code_to_pageviews + * 20190324155606_add_password_hash_to_users + * 20190402145007_remove_device_type_from_pageviews + * 20190402145357_remove_screen_height_from_pageviews + * 20190402172423_add_index_to_pageviews + * 20190410095248_add_feedback_emails + * 20190424162903_delete_feedback_emails_when_user_is_deleted + * 20190430140411_use_citext_for_email + * 20190430152923_create_subscriptions + * 20190516113517_remove_session_id_from_pageviews + * 20190520144229_change_user_id_to_uuid + * 20190523160838_add_raw_referrer + * 20190523171519_add_indices_to_referrers + * 20190618165016_add_public_sites + * 20190718160353_create_google_search_console_integration + * 20190723141824_associate_google_auth_with_site + * 20190730014913_add_monthly_stats + * 20190730142200_add_weekly_stats + * 20190730144413_add_daily_stats + * 20190809174105_calc_screen_size + * 20190810145419_remove_unused_indices + * 20190820140747_remove_rollup_tables + * 20190906111810_add_email_reporting + * 20190907134114_add_unique_index_to_email_settings + * 20190910120900_add_email_address_to_settings + * 20190911102027_add_monthly_reports + * 20191010031425_add_property_to_google_auth + * 20191015072730_remove_unused_fields + * 20191015073507_proper_timestamp_for_pageviews + * 20191024062200_rename_pageviews_to_events + * 20191025055334_add_name_to_events + * 20191031051340_add_goals + * 20191031063001_remove_goal_name + * 20191118075359_allow_free_subscriptions + * 20191216064647_add_unique_index_to_email_reports + * 20191218082207_add_sessions + * 20191220042658_add_session_start + * 20200106090739_cascade_google_auth_deletion + * 20200107095234_add_entry_page_to_sessions + * 20200113143927_add_exit_page_to_session + * 20200114131538_add_tweets + * 20200120091134_change_session_referrer_to_text + * 20200121091251_add_recipients + * 20200122150130_add_shared_links + * 20200130123049_add_site_id_to_events + * 20200204093801_rename_site_id_to_domain + * 20200204133522_drop_events_hostname_index + * 20200210134612_add_fingerprint_to_events + * 20200211080841_add_raw_fingerprint + * 20200211090126_remove_raw_fingerprint + * 20200211133829_add_initial_source_and_referrer_to_events + * 20200219124314_create_custom_domains + * 20200227092821_add_fingerprint_sesssions + * 20200302105632_flexible_fingerprint_referrer + * 20200317093028_add_trial_expiry_to_users + * 20200317142459_backfill_fingerprints + * 20200320100803_add_setup_emails + * 20200323083536_add_create_site_emails + * 20200323084954_add_check_stats_emails + * 20200324132431_make_cookie_fields_non_required + * 20200406115153_cascade_custom_domain_deletion + * 20200408122329_cascade_setup_emails_deletion + * 20200529071028_add_oban_jobs_table + * 20200605134616_remove_events_and_sessions + * 20200605142737_remove_fingerprint_sessions_table + * 20200619071221_create_salts_table + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20201106125234: + * 20200915070607_create_events_and_sessions + * 20200918075025_add_utm_tags + * 20201020083739_add_event_metadata + * 20201106125234_add_browser_version_and_os_version + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20210209095257: + * 20201130083829_add_email_verification_codes + * 20201208173543_add_spike_notifications + * 20201210085345_add_email_verified_to_users + * 20201214072008_add_theme_pref_to_users + * 20201230085939_delete_email_records_when_user_is_deleted + * 20210115092331_cascade_site_deletion_to_spike_notification + * 20210119093337_add_unique_index_to_spike_notification + * 20210128083453_cascade_site_deletion + * 20210128084657_create_api_keys + * 20210209095257_add_last_payment_details + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20210323130440: + * 20210323130440_add_sample_by + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20210629124428: + * 20210406073254_add_name_to_shared_links + * 20210409074413_add_unique_index_to_shared_link_name + * 20210409082603_add_api_key_scopes + * 20210420075623_add_sent_renewal_notifications + * 20210426075157_upgrade_oban_jobs_to_v9 + * 20210513091653_add_currency_to_subscription + * 20210525085655_add_rate_limit_to_api_keys + * 20210531080158_add_role_to_site_memberships + * 20210601090924_add_invitations + * 20210604085943_add_locked_to_sites + * 20210629124428_cascade_site_deletion_to_invitations + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20210712214034: + * 20210712214034_add_more_location_details + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20210908081119: + * 20210726090211_make_invitation_email_case_insensitive + * 20210906102736_memoize_setup_complete + * 20210908081119_allow_trial_expiry_to_be_null + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20211017093035: + * 20211017093035_add_utm_content_and_term + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20211110174617: + * 20211020093238_add_enterprise_plans + * 20211022084427_add_site_limit_to_enterprise_plans + * 20211028122202_grace_period_end + * 20211110174617_add_site_imported_source + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20211112130238: + * 20211112130238_create_imported_tables + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20211202094732: + * 20211202094732_remove_tweets + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20220404123000: + * 20220310104931_add_transferred_from + * 20220404123000_add_entry_props_to_session + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20220421074114: + * 20220405124819_add_stats_start_date + * 20220408071645_create_oban_peers + * 20220408080058_swap_primary_oban_indexes + * 20220421074114_create_feature_flags_table + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20220422075510: + * 20220421161259_remove_entry_props + * 20220422075510_add_entry_props + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20221228123226: + * 20221109082503_add_rate_limiting_to_sites + * 20221123104203_index_updated_at_for_sites + * 20221228123226_cascade_delete_sent_renewal_notifications + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20230214114402: + * 20230124140348_add_city_name_to_imported_locations + * 20230210140348_remove_city_name_to_imported_locations + * 20230214114402_create_ingest_counters_table + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20230301095227: + * 20230301095227_add_native_stats_start_date + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20230320094327: + * 20230320094327_create_v2_schemas + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20230417095029: + * 20230328062644_allow_domain_change + * 20230406110926_associate-goals-with-sites + * 20230410070312_fixup_goals_sites_assoc + * 20230417092745_add_monetary_value_to_goals + * 20230417095029_init_funnels + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20230417104025: + * 20230417104025_add_revenue_to_events + + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20230503094245: + * 20230503094245_add_event_prop_allowlist_to_site + + Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20230509124919: + * 20230509124919_clean_up_old_tables_after_v2_migration + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20231011101825: + * 20230516131041_add_unique_index_to_api_keys * 20230530161856_add_enable_feature_fields_for_site * 20230724131709_change_allowed_event_props_type * 20230802081520_cascade_delete_user @@ -332,13 +371,8 @@ defmodule Plausible.ReleaseTest do Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20240709181437: * 20240709181437_populate_location_data + Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version \ """ <> _future = pending_streaks - - # - # and finally migrate all the way up to to master - # - - _logs = capture_io(fn -> Release.interweave_migrate([PostgreSQL, ClickHouse]) end) end end end From 026efe85912968e5b741bf4a7b653bd8ef8f6805 Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Fri, 30 Aug 2024 11:23:41 +0700 Subject: [PATCH 15/20] only test v2+ --- test/plausible/release_test.exs | 208 ++++---------------------------- 1 file changed, 24 insertions(+), 184 deletions(-) diff --git a/test/plausible/release_test.exs b/test/plausible/release_test.exs index 8fbe8a4f3621..5804c03e3923 100644 --- a/test/plausible/release_test.exs +++ b/test/plausible/release_test.exs @@ -89,7 +89,30 @@ defmodule Plausible.ReleaseTest do :ok end - test "from scratch" do + defp fake_migrate(repo, up_to_migration) do + {up_to_version, _name} = Integer.parse(up_to_migration) + + Ecto.Migrator.with_repo(repo, fn repo -> + schema_versions = + Ecto.Migrator.migrations(repo) + |> Enum.filter(fn {status, version, _name} -> + status == :down and version <= up_to_version + end) + |> Enum.map(fn {_status, version, _name} -> + {version, NaiveDateTime.utc_now(:second)} + end) + + repo.insert_all("schema_versions", schema_versions) + end) + end + + test "v2.0.0 -> master" do + # pretend to migrate the repos up to v2.0.0 + # https://github.com/plausible/analytics/tree/v2.0.0/priv/repo/migrations + fake_migrate(PostgreSQL, _up_to = "20230516131041_add_unique_index_to_api_keys") + # https://github.com/plausible/analytics/tree/v2.0.0/priv/ingest_repo/migrations + fake_migrate(ClickHouse, _up_to = "20230509124919_clean_up_old_tables_after_v2_migration") + pending_streaks = capture_io(fn -> Release.pending_streaks([PostgreSQL, ClickHouse]) end) pending_streaks = @@ -106,190 +129,7 @@ defmodule Plausible.ReleaseTest do Starting repos.. Collecting pending migrations.. - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20200619071221: - * 20181201181549_add_pageviews - * 20181214201821_add_new_visitor_to_pageviews - * 20181215140923_add_session_id_to_pageviews - * 20190109173917_create_sites - * 20190117135714_add_uid_to_pageviews - * 20190118154210_add_derived_data_to_pageviews - * 20190126135857_add_name_to_users - * 20190127213938_add_tz_to_sites - * 20190205165931_add_last_seen_to_users - * 20190213224404_add_intro_emails - * 20190219130809_delete_intro_emails_when_user_is_deleted - * 20190301122344_add_country_code_to_pageviews - * 20190324155606_add_password_hash_to_users - * 20190402145007_remove_device_type_from_pageviews - * 20190402145357_remove_screen_height_from_pageviews - * 20190402172423_add_index_to_pageviews - * 20190410095248_add_feedback_emails - * 20190424162903_delete_feedback_emails_when_user_is_deleted - * 20190430140411_use_citext_for_email - * 20190430152923_create_subscriptions - * 20190516113517_remove_session_id_from_pageviews - * 20190520144229_change_user_id_to_uuid - * 20190523160838_add_raw_referrer - * 20190523171519_add_indices_to_referrers - * 20190618165016_add_public_sites - * 20190718160353_create_google_search_console_integration - * 20190723141824_associate_google_auth_with_site - * 20190730014913_add_monthly_stats - * 20190730142200_add_weekly_stats - * 20190730144413_add_daily_stats - * 20190809174105_calc_screen_size - * 20190810145419_remove_unused_indices - * 20190820140747_remove_rollup_tables - * 20190906111810_add_email_reporting - * 20190907134114_add_unique_index_to_email_settings - * 20190910120900_add_email_address_to_settings - * 20190911102027_add_monthly_reports - * 20191010031425_add_property_to_google_auth - * 20191015072730_remove_unused_fields - * 20191015073507_proper_timestamp_for_pageviews - * 20191024062200_rename_pageviews_to_events - * 20191025055334_add_name_to_events - * 20191031051340_add_goals - * 20191031063001_remove_goal_name - * 20191118075359_allow_free_subscriptions - * 20191216064647_add_unique_index_to_email_reports - * 20191218082207_add_sessions - * 20191220042658_add_session_start - * 20200106090739_cascade_google_auth_deletion - * 20200107095234_add_entry_page_to_sessions - * 20200113143927_add_exit_page_to_session - * 20200114131538_add_tweets - * 20200120091134_change_session_referrer_to_text - * 20200121091251_add_recipients - * 20200122150130_add_shared_links - * 20200130123049_add_site_id_to_events - * 20200204093801_rename_site_id_to_domain - * 20200204133522_drop_events_hostname_index - * 20200210134612_add_fingerprint_to_events - * 20200211080841_add_raw_fingerprint - * 20200211090126_remove_raw_fingerprint - * 20200211133829_add_initial_source_and_referrer_to_events - * 20200219124314_create_custom_domains - * 20200227092821_add_fingerprint_sesssions - * 20200302105632_flexible_fingerprint_referrer - * 20200317093028_add_trial_expiry_to_users - * 20200317142459_backfill_fingerprints - * 20200320100803_add_setup_emails - * 20200323083536_add_create_site_emails - * 20200323084954_add_check_stats_emails - * 20200324132431_make_cookie_fields_non_required - * 20200406115153_cascade_custom_domain_deletion - * 20200408122329_cascade_setup_emails_deletion - * 20200529071028_add_oban_jobs_table - * 20200605134616_remove_events_and_sessions - * 20200605142737_remove_fingerprint_sessions_table - * 20200619071221_create_salts_table - - Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20201106125234: - * 20200915070607_create_events_and_sessions - * 20200918075025_add_utm_tags - * 20201020083739_add_event_metadata - * 20201106125234_add_browser_version_and_os_version - - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20210209095257: - * 20201130083829_add_email_verification_codes - * 20201208173543_add_spike_notifications - * 20201210085345_add_email_verified_to_users - * 20201214072008_add_theme_pref_to_users - * 20201230085939_delete_email_records_when_user_is_deleted - * 20210115092331_cascade_site_deletion_to_spike_notification - * 20210119093337_add_unique_index_to_spike_notification - * 20210128083453_cascade_site_deletion - * 20210128084657_create_api_keys - * 20210209095257_add_last_payment_details - - Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20210323130440: - * 20210323130440_add_sample_by - - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20210629124428: - * 20210406073254_add_name_to_shared_links - * 20210409074413_add_unique_index_to_shared_link_name - * 20210409082603_add_api_key_scopes - * 20210420075623_add_sent_renewal_notifications - * 20210426075157_upgrade_oban_jobs_to_v9 - * 20210513091653_add_currency_to_subscription - * 20210525085655_add_rate_limit_to_api_keys - * 20210531080158_add_role_to_site_memberships - * 20210601090924_add_invitations - * 20210604085943_add_locked_to_sites - * 20210629124428_cascade_site_deletion_to_invitations - - Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20210712214034: - * 20210712214034_add_more_location_details - - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20210908081119: - * 20210726090211_make_invitation_email_case_insensitive - * 20210906102736_memoize_setup_complete - * 20210908081119_allow_trial_expiry_to_be_null - - Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20211017093035: - * 20211017093035_add_utm_content_and_term - - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20211110174617: - * 20211020093238_add_enterprise_plans - * 20211022084427_add_site_limit_to_enterprise_plans - * 20211028122202_grace_period_end - * 20211110174617_add_site_imported_source - - Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20211112130238: - * 20211112130238_create_imported_tables - - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20211202094732: - * 20211202094732_remove_tweets - - Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20220404123000: - * 20220310104931_add_transferred_from - * 20220404123000_add_entry_props_to_session - - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20220421074114: - * 20220405124819_add_stats_start_date - * 20220408071645_create_oban_peers - * 20220408080058_swap_primary_oban_indexes - * 20220421074114_create_feature_flags_table - - Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20220422075510: - * 20220421161259_remove_entry_props - * 20220422075510_add_entry_props - - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20221228123226: - * 20221109082503_add_rate_limiting_to_sites - * 20221123104203_index_updated_at_for_sites - * 20221228123226_cascade_delete_sent_renewal_notifications - - Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20230214114402: - * 20230124140348_add_city_name_to_imported_locations - * 20230210140348_remove_city_name_to_imported_locations - * 20230214114402_create_ingest_counters_table - - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20230301095227: - * 20230301095227_add_native_stats_start_date - - Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20230320094327: - * 20230320094327_create_v2_schemas - - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20230417095029: - * 20230328062644_allow_domain_change - * 20230406110926_associate-goals-with-sites - * 20230410070312_fixup_goals_sites_assoc - * 20230417092745_add_monetary_value_to_goals - * 20230417095029_init_funnels - - Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20230417104025: - * 20230417104025_add_revenue_to_events - - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20230503094245: - * 20230503094245_add_event_prop_allowlist_to_site - - Plausible.ReleaseTest.ClickHouse [_build/test/lib/plausible/priv/ingest_repo/migrations] streak up to version 20230509124919: - * 20230509124919_clean_up_old_tables_after_v2_migration - Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version 20231011101825: - * 20230516131041_add_unique_index_to_api_keys * 20230530161856_add_enable_feature_fields_for_site * 20230724131709_change_allowed_event_props_type * 20230802081520_cascade_delete_user From 1d8d84e4ec3cfd74d153d018054ff5af1203a0a6 Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Fri, 30 Aug 2024 11:27:26 +0700 Subject: [PATCH 16/20] fix test --- test/plausible/release_test.exs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/plausible/release_test.exs b/test/plausible/release_test.exs index 5804c03e3923..8ce4bcd0aa2b 100644 --- a/test/plausible/release_test.exs +++ b/test/plausible/release_test.exs @@ -92,6 +92,13 @@ defmodule Plausible.ReleaseTest do defp fake_migrate(repo, up_to_migration) do {up_to_version, _name} = Integer.parse(up_to_migration) + insert_opts = + if repo == ClickHouse do + [types: [version: "Int64", inserted_at: "DateTime"]] + else + [] + end + Ecto.Migrator.with_repo(repo, fn repo -> schema_versions = Ecto.Migrator.migrations(repo) @@ -99,10 +106,10 @@ defmodule Plausible.ReleaseTest do status == :down and version <= up_to_version end) |> Enum.map(fn {_status, version, _name} -> - {version, NaiveDateTime.utc_now(:second)} + [version: version, inserted_at: NaiveDateTime.utc_now(:second)] end) - repo.insert_all("schema_versions", schema_versions) + repo.insert_all("schema_migrations", schema_versions, insert_opts) end) end From a235e35644226b1797770d7c0478675b53df3af5 Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Fri, 30 Aug 2024 11:28:27 +0700 Subject: [PATCH 17/20] return async: true --- test/plausible/release_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/plausible/release_test.exs b/test/plausible/release_test.exs index 8ce4bcd0aa2b..767e7efb80bb 100644 --- a/test/plausible/release_test.exs +++ b/test/plausible/release_test.exs @@ -1,5 +1,5 @@ defmodule Plausible.ReleaseTest do - use Plausible.DataCase, async: false + use Plausible.DataCase, async: true alias Plausible.{Release, Auth} import ExUnit.CaptureIO From b8c6bc88b8bb3d2715631010d6758f3a22289e9c Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Fri, 30 Aug 2024 11:40:05 +0700 Subject: [PATCH 18/20] cleanup --- lib/plausible_release.ex | 66 ++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index 99505b9efd08..f268925f9528 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -65,33 +65,22 @@ defmodule Plausible.Release do def interweave_migrate(repos \\ repos()) do prepare() - streaks = migration_streaks(repos) + pending = all_pending_migrations(repos) + streaks = migration_streaks(pending) Enum.each(streaks, fn {repo, up_to_version} -> {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, to: up_to_version)) end) end - @doc false - def migration_streaks(repos) do - all_pending = - Enum.flat_map(repos, fn repo -> - # credo:disable-for-lines:6 Credo.Check.Refactor.Nesting - {:ok, pending, _started} = - Ecto.Migrator.with_repo(repo, fn repo -> - Ecto.Migrator.migrations(repo) - |> Enum.filter(fn {status, _version, _name} -> status == :down end) - |> Enum.map(fn {_status, version, _name} -> {repo, version} end) - end) - - pending - end) - - all_sorted = - Enum.sort_by(all_pending, fn {_repo, version} -> version end, :asc) + defp migration_streaks(pending_migrations) do + sorted_migrations = + pending_migrations + |> Enum.map(fn {repo, version, _name} -> {repo, version} end) + |> Enum.sort_by(fn {_repo, version} -> version end, :asc) streaks_reversed = - Enum.reduce(all_sorted, [], fn {repo, _version} = latest_migration, streaks_acc -> + Enum.reduce(sorted_migrations, [], fn {repo, _version} = latest_migration, streaks_acc -> case streaks_acc do # start the streak for repo [] -> [latest_migration] @@ -105,6 +94,21 @@ defmodule Plausible.Release do :lists.reverse(streaks_reversed) end + @spec all_pending_migrations([Ecto.Repo.t()]) :: [{Ecto.Repo.t(), integer, String.t()}] + defp all_pending_migrations(repos) do + Enum.flat_map(repos, fn repo -> + # credo:disable-for-lines:6 Credo.Check.Refactor.Nesting + {:ok, pending, _started} = + Ecto.Migrator.with_repo(repo, fn repo -> + Ecto.Migrator.migrations(repo) + |> Enum.filter(fn {status, _version, _name} -> status == :down end) + |> Enum.map(fn {_status, version, name} -> {repo, version, name} end) + end) + + pending + end) + end + def pending_migrations do prepare() IO.puts("Pending migrations") @@ -116,25 +120,13 @@ defmodule Plausible.Release do prepare() IO.puts("Collecting pending migrations..\n") - streaks = migration_streaks(repos) - - all_pending = - Enum.flat_map(repos, fn repo -> - # credo:disable-for-lines:6 Credo.Check.Refactor.Nesting - {:ok, pending, _started} = - Ecto.Migrator.with_repo(repo, fn repo -> - Ecto.Migrator.migrations(repo) - |> Enum.filter(fn {status, _version, _name} -> status == :down end) - |> Enum.map(fn {_status, version, name} -> {repo, version, name} end) - end) - - pending - end) + pending = all_pending_migrations(repos) + streaks = migration_streaks(pending) - print_streaks(streaks, all_pending) + print_migration_streaks(streaks, pending) end - defp print_streaks([{repo, up_to_version} | streaks], pending) do + defp print_migration_streaks([{repo, up_to_version} | streaks], pending) do {streak, pending} = Enum.split_with(pending, fn {pending_repo, version, _name} -> pending_repo == repo and version <= up_to_version @@ -147,10 +139,10 @@ defmodule Plausible.Release do Enum.each(streak, fn {_repo, version, name} -> IO.puts(" * #{version}_#{name}") end) IO.puts("") - print_streaks(streaks, pending) + print_migration_streaks(streaks, pending) end - defp print_streaks([], []), do: :ok + defp print_migration_streaks([], []), do: :ok def seed do prepare() From 92f9490bacd5926694b1acecf224e5841a288e96 Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Sat, 31 Aug 2024 10:12:37 +0700 Subject: [PATCH 19/20] add 'no pending migration' --- lib/plausible_release.ex | 14 ++++++++------ test/plausible/release_test.exs | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index f268925f9528..3015b0881d27 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -118,12 +118,16 @@ defmodule Plausible.Release do def pending_streaks(repos \\ repos()) do prepare() - IO.puts("Collecting pending migrations..\n") + IO.puts("Collecting pending migrations..") pending = all_pending_migrations(repos) - streaks = migration_streaks(pending) - print_migration_streaks(streaks, pending) + if pending == [] do + IO.puts("No pending migrations!") + else + streaks = migration_streaks(pending) + print_migration_streaks(streaks, pending) + end end defp print_migration_streaks([{repo, up_to_version} | streaks], pending) do @@ -133,12 +137,10 @@ defmodule Plausible.Release do end) IO.puts( - "#{inspect(repo)} [#{Path.relative_to_cwd(Ecto.Migrator.migrations_path(repo))}] streak up to version #{up_to_version}:" + "\n#{inspect(repo)} [#{Path.relative_to_cwd(Ecto.Migrator.migrations_path(repo))}] streak up to version #{up_to_version}:" ) Enum.each(streak, fn {_repo, version, name} -> IO.puts(" * #{version}_#{name}") end) - IO.puts("") - print_migration_streaks(streaks, pending) end diff --git a/test/plausible/release_test.exs b/test/plausible/release_test.exs index 767e7efb80bb..1664c744eea8 100644 --- a/test/plausible/release_test.exs +++ b/test/plausible/release_test.exs @@ -89,6 +89,17 @@ defmodule Plausible.ReleaseTest do :ok end + defp last_migration(repo) do + {:ok, {_status, version, name}, _started} = + Ecto.Migrator.with_repo(repo, fn repo -> + repo + |> Ecto.Migrator.migrations() + |> List.last() + end) + + "#{version}_#{name}" + end + defp fake_migrate(repo, up_to_migration) do {up_to_version, _name} = Integer.parse(up_to_migration) @@ -220,6 +231,19 @@ defmodule Plausible.ReleaseTest do Plausible.ReleaseTest.PostgreSQL [_build/test/lib/plausible/priv/repo/migrations] streak up to version \ """ <> _future = pending_streaks + + fake_migrate(PostgreSQL, last_migration(PostgreSQL)) + fake_migrate(ClickHouse, last_migration(ClickHouse)) + + no_streaks = capture_io(fn -> Release.pending_streaks([PostgreSQL, ClickHouse]) end) + + assert no_streaks == """ + Loading plausible.. + Starting dependencies.. + Starting repos.. + Collecting pending migrations.. + No pending migrations! + """ end end end From de576a363b971365ef9393fcacd871c8bbbe7596 Mon Sep 17 00:00:00 2001 From: ruslandoga <67764432+ruslandoga@users.noreply.github.com> Date: Sat, 7 Sep 2024 17:06:47 +0700 Subject: [PATCH 20/20] drop migrate/0 and pending_migrations/0 --- lib/plausible_release.ex | 42 +--------------------------------------- 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/lib/plausible_release.ex b/lib/plausible_release.ex index 3015b0881d27..2afdb36468cd 100644 --- a/lib/plausible_release.ex +++ b/lib/plausible_release.ex @@ -19,14 +19,8 @@ defmodule Plausible.Release do end end - def migrate do - prepare() - Enum.each(repos(), &run_migrations_for/1) - IO.puts("Migrations successful!") - end - @doc """ - `interweave_migrate/0` is a more advanced (compared to `migrate/0`) migration function that: + `interweave_migrate/0` is a migration function that: - Lists all pending migrations across multiple repositories. - Sorts these migrations into a single list. @@ -109,13 +103,6 @@ defmodule Plausible.Release do end) end - def pending_migrations do - prepare() - IO.puts("Pending migrations") - IO.puts("") - Enum.each(repos(), &list_pending_migrations_for/1) - end - def pending_streaks(repos \\ repos()) do prepare() IO.puts("Collecting pending migrations..") @@ -237,33 +224,6 @@ defmodule Plausible.Release do end end - defp run_migrations_for(repo) do - IO.puts("Running migrations for #{repo}") - {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true)) - end - - defp list_pending_migrations_for(repo) do - IO.puts("Listing pending migrations for #{repo}") - IO.puts("") - - migration_directory = Ecto.Migrator.migrations_path(repo) - - pending = - repo - |> Ecto.Migrator.migrations([migration_directory]) - |> Enum.filter(fn {status, _version, _migration} -> status == :down end) - - if pending == [] do - IO.puts("No pending migrations") - else - Enum.each(pending, fn {_, version, migration} -> - IO.puts("* #{version}_#{migration}") - end) - end - - IO.puts("") - end - defp ensure_repo_created(repo) do IO.puts("create #{inspect(repo)} database if it doesn't exist")