Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent message extractor from crash and log warning on obsolete migration #101

Merged
merged 5 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ If you're working on an Elixir/Phoenix project and need to manage translations,
- Elixir (tested on 1.14.0)
- Phoenix (tested on 1.7.0)
- Ecto SQL (tested on 3.6)
- PostgreSQL 15+ or SQLite 3.31.0+

## Installation

Expand Down Expand Up @@ -181,9 +182,9 @@ In the `application.ex` file of our project, we add Kanta and its configuration

## Kanta UI

Inside your `router.ex` file we need to connect the Kanta panel using the kanta_dashboard macro.
Inside your `router.ex` file we need to connect the Kanta panel using the kanta_dashboard macro.

```elixir
```elixir
import KantaWeb.Router

scope "/" do
Expand Down Expand Up @@ -227,7 +228,7 @@ Not all of us are polyglots, and sometimes we need the help of machine translati

```elixir
# mix.exs
defp deps do
defp deps do
...
{:kanta_deep_l_plugin, "~> 0.1.1"}
end
Expand All @@ -242,27 +243,27 @@ config :kanta,
]
```

## KantaSync
## KantaSync

The [KantaSync plugin](https://github.com/curiosum-dev/kanta_sync_plugin) allows you to synchronize translations between your production and staging/dev environments. It ensures that any changes made to translations in one are reflected in the others, helping you maintain consistency across different stages of development.

```elixir
# mix.exs
defp deps do
```elixir
# mix.exs
defp deps do
...
{:kanta_sync_plugin, "~> 0.1.0"}
end
```

You need to have Kanta API configured by using kanta_api macro.
You need to have Kanta API configured by using kanta_api macro.

```elixir
# router.ex
# router.ex
import KantaWeb.Router

scope "/" do
scope "/" do
kanta_api("/kanta-api")
end
end
```

### Authorization
Expand Down
1 change: 1 addition & 0 deletions lib/kanta.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ defmodule Kanta do
@impl Supervisor
def init(%Config{plugins: plugins} = conf) do
children = [
{Kanta.MigrationVersionChecker, []},
{MessagesExtractorAgent, conf: conf, name: Registry.via(conf.name, MessagesExtractorAgent)}
]

Expand Down
88 changes: 88 additions & 0 deletions lib/kanta/migration_version_checker.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
defmodule Kanta.MigrationVersionChecker do
@moduledoc """
GenServer responsible for checking if a new migration version is available for Kanta.

This module runs a version check when started to compare the current database migration
version against the latest available version. If a newer version is available, it displays
a formatted warning message in the console with:

- Current and latest version numbers
- Step-by-step instructions for updating
- Commands to generate and run the required migrations

The checker supports both PostgreSQL and SQLite3 databases and automatically detects
which adapter is being used.
"""

use GenServer

@colors [
warning: :yellow,
highlight: :cyan,
brand: :magenta,
reset: :reset
]

def start_link(_opts) do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end

@impl true
def init(_) do
check_version()

{:ok, %{}}
end

defp check_version do
migrator =
case Kanta.Repo.get_adapter_name() do
:postgres -> Kanta.Migrations.Postgresql
:sqlite -> Kanta.Migrations.SQLite3
end

latest_version = migrator.current_version()
migrated = migrator.migrated_version(%{repo: Kanta.Repo.get_repo()})

if migrated < latest_version do
warning_message = """
#{colorize("⚠️ [Kanta Migration Alert]", @colors[:warning])}
#{colorize("━━━━━━━━━━━━━━━━━━━━━━━━━━", @colors[:brand])}

A new version of Kanta migrations is available for your database!

Current version: #{colorize(to_string(migrated), @colors[:highlight])}
Latest version: #{colorize(to_string(latest_version), @colors[:highlight])}

To ensure optimal performance and functionality, please update your database schema.

📝 Here's what you need to do:

1. Generate a new migration:
#{colorize("$ mix ecto.gen.migration update_kanta_migrations", @colors[:brand])}

2. Add the following to your migration file:
#{colorize("def up do", @colors[:highlight])}
#{colorize("Kanta.Migration.up(version: #{latest_version})", @colors[:highlight])}
#{colorize("end", @colors[:highlight])}

#{colorize("def down do", @colors[:highlight])}
#{colorize("Kanta.Migration.down(version: #{latest_version})", @colors[:highlight])}
#{colorize("end", @colors[:highlight])}

3. Run the migration:
#{colorize("$ mix ecto.migrate", @colors[:brand])}

📚 For more details, visit the Kanta documentation.
#{colorize("━━━━━━━━━━━━━━━━━━━━━━━━━━", @colors[:brand])}
"""

IO.puts(warning_message)
end
end

defp colorize(text, color) do
IO.ANSI.format([color, text, @colors[:reset]])
|> IO.chardata_to_string()
end
end
20 changes: 19 additions & 1 deletion lib/kanta/po_files/messages_extractor_agent.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,26 @@ defmodule Kanta.POFiles.MessagesExtractorAgent do

@impl true
def init(_) do
MessagesExtractor.call()
if message_extractor_available?() do
MessagesExtractor.call()
end

{:ok, %{}}
end

defp message_extractor_available? do
# Message extractor requires columns added in version 3 of Postgres migration and version 2 of SQLite migration.
migrator =
case Kanta.Repo.get_adapter_name() do
:postgres -> Kanta.Migrations.Postgresql
:sqlite -> Kanta.Migrations.SQLite3
end

migrated_version = migrator.migrated_version(%{repo: Kanta.Repo.get_repo()})

case Kanta.Repo.get_adapter_name() do
:postgres -> migrated_version >= 3
:sqlite -> migrated_version >= 2
end
end
end
7 changes: 7 additions & 0 deletions lib/kanta/repo.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,11 @@ defmodule Kanta.Repo do
def get_repo do
Kanta.config().repo
end

def get_adapter_name do
case get_repo().__adapter__() do
Ecto.Adapters.Postgres -> :postgres
Ecto.Adapters.SQLite3 -> :sqlite
end
end
end
Loading