ecto-release-migrations
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseEcto Release Migrations Setup
Ecto版本迁移设置
Overview
概述
In Elixir releases, Mix is not available. This skill creates a Release module that handles database creation, migration, and rollback via commands.
bin/app_name eval在Elixir版本发布中,Mix不可用。本技能会创建一个Release模块,通过命令处理数据库创建、迁移和回滚操作。
bin/app_name evalWorkflow
工作流程
-
Detect app name and repos
- Check for app name
mix.exs - Check or
config/config.exsfor Ecto reposconfig/runtime.exs
- Check
-
Create Release module
- Location:
lib/<app_name>/release.ex - Must handle multiple repos if present
- Location:
-
Verify config
- Ensure has production database config
config/runtime.exs - Check for or explicit config
DATABASE_URL
- Ensure
-
检测应用名称和仓库
- 检查获取应用名称
mix.exs - 检查或
config/config.exs获取Ecto仓库config/runtime.exs
- 检查
-
创建Release模块
- 位置:
lib/<app_name>/release.ex - 若存在多个仓库,必须支持多仓库处理
- 位置:
-
验证配置
- 确保包含生产环境数据库配置
config/runtime.exs - 检查是否存在或显式配置
DATABASE_URL
- 确保
Implementation
实现
Release Module Template
Release模块模板
elixir
defmodule <AppName>.Release do
@moduledoc """
Release tasks for database management.
Usage in production:
bin/<app_name> eval "<AppName>.Release.migrate()"
bin/<app_name> eval "<AppName>.Release.rollback(<AppName>.Repo, 20240101000000)"
"""
@app :<app_name>
def migrate do
load_app()
for repo <- repos() do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
end
end
def rollback(repo, version) do
load_app()
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
end
def create do
load_app()
for repo <- repos() do
case repo.__adapter__().storage_up(repo.config()) do
:ok -> IO.puts("Database created for #{inspect(repo)}")
{:error, :already_up} -> IO.puts("Database already exists for #{inspect(repo)}")
{:error, term} -> raise "Failed to create database: #{inspect(term)}"
end
end
end
def seed do
load_app()
for repo <- repos() do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, fn _repo ->
seed_file = Application.app_dir(@app, "priv/repo/seeds.exs")
if File.exists?(seed_file) do
Code.eval_file(seed_file)
end
end)
end
end
defp repos do
Application.fetch_env!(@app, :ecto_repos)
end
defp load_app do
Application.ensure_all_started(:ssl)
Application.load(@app)
end
endelixir
defmodule <AppName>.Release do
@moduledoc """
Release tasks for database management.
Usage in production:
bin/<app_name> eval "<AppName>.Release.migrate()"
bin/<app_name> eval "<AppName>.Release.rollback(<AppName>.Repo, 20240101000000)"
"""
@app :<app_name>
def migrate do
load_app()
for repo <- repos() do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
end
end
def rollback(repo, version) do
load_app()
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
end
def create do
load_app()
for repo <- repos() do
case repo.__adapter__().storage_up(repo.config()) do
:ok -> IO.puts("Database created for #{inspect(repo)}")
{:error, :already_up} -> IO.puts("Database already exists for #{inspect(repo)}")
{:error, term} -> raise "Failed to create database: #{inspect(term)}"
end
end
end
def seed do
load_app()
for repo <- repos() do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, fn _repo ->
seed_file = Application.app_dir(@app, "priv/repo/seeds.exs")
if File.exists?(seed_file) do
Code.eval_file(seed_file)
end
end)
end
end
defp repos do
Application.fetch_env!(@app, :ecto_repos)
end
defp load_app do
Application.ensure_all_started(:ssl)
Application.load(@app)
end
endFor Phoenix Projects with Multiple Repos
针对多仓库的Phoenix项目
If multiple repos exist (e.g., and ), ensure has:
RepoReadRepoconfig.exselixir
config :<app_name>, ecto_repos: [<AppName>.Repo, <AppName>.ReadRepo]若存在多个仓库(例如和),确保中包含:
RepoReadRepoconfig.exselixir
config :<app_name>, ecto_repos: [<AppName>.Repo, <AppName>.ReadRepo]Verification Steps
验证步骤
After creating the module:
- Compile:
mix compile - Test locally:
mix run -e "<AppName>.Release.migrate()" - Build release:
MIX_ENV=prod mix release - Test release:
_build/prod/rel/<app_name>/bin/<app_name> eval "<AppName>.Release.migrate()"
创建模块后:
- 编译:
mix compile - 本地测试:
mix run -e "<AppName>.Release.migrate()" - 构建版本:
MIX_ENV=prod mix release - 测试版本:
_build/prod/rel/<app_name>/bin/<app_name> eval "<AppName>.Release.migrate()"
Usage Documentation
使用文档
Add to project README or deployment docs:
bash
undefined添加到项目README或部署文档中:
bash
undefinedCreate database (first deploy only)
创建数据库(仅首次部署时使用)
bin/<app_name> eval "<AppName>.Release.migrate()"
bin/<app_name> eval "<AppName>.Release.migrate()"
Run migrations
运行迁移
bin/<app_name> eval "<AppName>.Release.migrate()"
bin/<app_name> eval "<AppName>.Release.migrate()"
Rollback to specific version
回滚到指定版本
bin/<app_name> eval "<AppName>.Release.rollback(<AppName>.Repo, 20240101000000)"
bin/<app_name> eval "<AppName>.Release.rollback(<AppName>.Repo, 20240101000000)"
Seed database
填充数据库初始数据
bin/<app_name> eval "<AppName>.Release.seed()"
undefinedbin/<app_name> eval "<AppName>.Release.seed()"
undefinedCommon Issues
常见问题
- SSL not started: Ensure is called before repo operations
Application.ensure_all_started(:ssl) - App not loaded: Always call first
Application.load(@app) - Missing ecto_repos config: Verify exists
config :app_name, ecto_repos: [...]
- SSL未启动:确保在仓库操作前调用
Application.ensure_all_started(:ssl) - 应用未加载:始终先调用
Application.load(@app) - 缺少ecto_repos配置:验证是否存在配置
config :app_name, ecto_repos: [...]