Referência de CLI
merql inclui uma CLI para capturar snapshots, calcular diferenças e executar mesclagens diretamente pelo terminal. Composer a instala como vendor/bin/merql; em um checkout do repositório merql, ela é bin/merql.
vendor/bin/merql funciona a partir de uma instalação de dependência porque merql 0.4.1. Versões anteriores procuravam o autoloader Composer apenas no diretório vendor/ do próprio pacote e falhavam quando merql era instalado como dependência.
Início rápido
# Capture a baseline from your database.
export MERQL_DB_DSN="sqlite:/path/to/db.sqlite"
vendor/bin/merql snapshot base
# Make some changes, then capture again.
vendor/bin/merql snapshot current
# See what changed.
vendor/bin/merql diff base current
Uma mesclagem de três vias exige que ours e theirs sejam capturados de dois bancos de dados que divergiram da base. Aponte MERQL_DB_DSN para o banco de dados correto para cada snapshot:
# Base: live before the sandbox was copied from it.
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot base
# ... copy live.sqlite to sandbox.sqlite, then both databases change ...
MERQL_DB_DSN="sqlite:/data/sandbox.sqlite" vendor/bin/merql snapshot ours
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot theirs
# Three-way merge with dry-run preview.
vendor/bin/merql merge base ours theirs --dry-run
Capturar os três snapshots do mesmo banco de dados, um após o outro, não funciona como mesclagem: theirs já conteria as alterações de ours, então cada linha inserida por ours seria relatada como um conflito insert_insert.
Variáveis de ambiente
O CLI lê os detalhes da conexão do banco de dados a partir de variáveis de ambiente. Você pode conectar usando uma string DSN do PDO ou parâmetros MySQL individuais.
Conexão baseada em DSN
Use MERQL_DB_DSN para conexões baseadas em PDO. Essa é a abordagem recomendada
para SQLite e para configurações não padrão. O DSN deve apontar para um banco de dados MySQL
ou SQLite: o CLI não tem como registrar um driver para outros mecanismos.
| Variável | Descrição | Exemplo |
|---|---|---|
MERQL_DB_DSN |
String DSN completa do PDO | sqlite:/path/to/db.sqlite |
MERQL_DB_USER |
Nome de usuário (opcional com DSN) | root |
MERQL_DB_PASS |
Senha (opcional com DSN) | secret |
# SQLite file.
export MERQL_DB_DSN="sqlite:/var/data/myapp.sqlite"
# MySQL via DSN.
export MERQL_DB_DSN="mysql:host=127.0.0.1;dbname=mydb;charset=utf8mb4"
export MERQL_DB_USER="root"
export MERQL_DB_PASS="secret"
Use um banco de dados SQLite baseado em arquivo. Cada comando CLI é executado em seu próprio processo, portanto
sqlite::memory: sempre abre um banco de dados novo e vazio, e um snapshot dele
não contém tabelas.
Atalho de MySQL
Quando MERQL_DB_DSN não está definido, o CLI recorre às variáveis específicas de MySQL.
| Variável | Padrão | Descrição |
|---|---|---|
MERQL_DB_NAME |
(obrigatório) | Nome do banco de dados |
MERQL_DB_HOST |
127.0.0.1 |
Host de MySQL |
MERQL_DB_PORT |
3306 |
Porta de MySQL |
MERQL_DB_USER |
root |
Nome de usuário de MySQL |
MERQL_DB_PASS |
(vazio) | Senha de MySQL |
MERQL_DB_ADAPTER |
pdo |
Defina como mysqli para usar o adaptador mysqli |
export MERQL_DB_NAME="wordpress"
export MERQL_DB_HOST="127.0.0.1"
export MERQL_DB_PORT="3306"
export MERQL_DB_USER="root"
export MERQL_DB_PASS="password"
Comandos
merql snapshot <name>
Capture o estado atual do banco de dados indicado pelas variáveis de ambiente e salve-o como um snapshot nomeado. Este é o único comando que se conecta a um banco de dados.
vendor/bin/merql snapshot baseline
Saída:
Snapshot 'baseline' saved
Tables: posts, comments, users, settings
Os snapshots são persistidos como arquivos JSON em .merql/snapshots/ no diretório de trabalho (consulte Armazenamento de snapshots). O nome deve conter apenas caracteres alfanuméricos, hífens e sublinhados.
Fluxo de trabalho típico: capture um snapshot antes de fazer alterações e depois capture outro. Os dois snapshots formam a base de uma comparação ou mesclagem.
merql diff <base> <current>
Compare dois snapshots nomeados e exiba um resumo das diferenças.
vendor/bin/merql diff baseline current
Saída:
Changeset: baseline -> current
Inserts: 3
Updates: 7
Deletes: 1
Os dois snapshots já devem existir (capturados anteriormente com merql snapshot). A comparação não exige conexão com um banco de dados, pois opera em arquivos de snapshot salvos.
merql merge <base> <ours> <theirs>
Faça uma mesclagem de três vias de três snapshots nomeados.
vendor/bin/merql merge base ours theirs
Saída:
Merge: base + ours + theirs
Operations: 12
Conflicts: 0
Clean: yes
Os três snapshots já devem existir. A mesclagem não exige conexão com um banco de dados, pois opera em arquivos de snapshot salvos, e nunca grava em um banco de dados: a CLI não tem comando de aplicação. Use o PHP API para aplicar um resultado de mesclagem.
O CLI mescla no nível da coluna. Ele não aplica mesclagem no nível da célula às colunas TEXT ou JSON, portanto duas edições diferentes na mesma coluna sempre geram um conflito aqui (#7). Use ThreeWayMerge com um CellMergeConfig em PHP para mesclagem no nível da célula.
--dry-run
Adicione a opção --dry-run para visualizar as instruções SQL que a mesclagem geraria, sem executar nada. As instruções descrevem como transformar o estado base no resultado mesclado, portanto incluem as alterações dos dois lados.
vendor/bin/merql merge base ours theirs --dry-run
Saída:
Merge: base + ours + theirs
Operations: 3
Conflicts: 0
Clean: yes
Dry run SQL:
INSERT INTO `posts` (`id`, `title`, `status`) VALUES ('10', 'New Post', 'draft');
UPDATE `posts` SET `title` = 'Updated Title' WHERE `id` = '5';
DELETE FROM `comments` WHERE `id` = '3';
Comandos de desenvolvimento
Um checkout do repositório merql tem mais scripts em bin/ para sua suíte de testes orientada por oráculo. Eles não fazem parte do pacote Composer, portanto uma instalação de dependência só tem vendor/bin/merql. Execute-os na raiz do repositório depois de composer install.
| Comando | Descrição |
|---|---|
./bin/oracle <name> |
Calcula o resultado esperado da mesclagem para um cenário |
./bin/actual <name> |
Executa merql em um cenário e captura a saída |
./bin/compare <name> |
Compara a saída do oráculo com a saída real |
./bin/test-scenario <name> |
Fluxo completo: configuração, oráculo, execução, comparação |
./bin/test-regression |
Executa todos os cenários |
./bin/test-regression --category clean |
Executa uma categoria: clean, conflict, identity, types, scale ou edge |
./bin/test-regression --fast |
Somente aprovação/reprovação, sem relatórios |
./bin/verify-compliance |
Relatório completo de conformidade |
./bin/verify-all |
PHPStan + estilo de código + PHPUnit + regressão do oráculo |
bin/test-regression também aceita --jobs, mas atualmente ignora o valor e executa os cenários um após o outro (#5). Uma opção --category desconhecida exibe No scenarios found e termina com sucesso.
Consulte Estratégia de testes para ver a estrutura dos cenários.
Código de saída
merql snapshot, diff e merge terminam com status 1 quando falta um argumento, assim como snapshot quando nenhuma conexão está configurada. A falta de um snapshot encerra o comando com uma exceção SnapshotException não capturada e status diferente de zero. Um comando desconhecido exibe Unknown command, mas atualmente termina com status 0 (#3).
Armazenamento de snapshots
Os snapshots são armazenados em .merql/snapshots/ em relação ao diretório de trabalho. Cada snapshot é um único arquivo JSON chamado <name>.json. Execute todos os comandos no mesmo diretório para que encontrem os snapshots uns dos outros.
A CLI não tem opção nem variável de ambiente para outro local (#8). Para usar outro local, mude para um diretório de trabalho diferente antes de executá-la. Em PHP, defina o diretório antes de capturar ou carregar snapshots:
use Merql\Snapshot\SnapshotStore;
SnapshotStore::setDirectory('/var/data/merql-snapshots');
Os arquivos de snapshot são portáteis. Você pode copiá-los entre máquinas, incluí-los no controle de versão ou compartilhá-los para depuração colaborativa. Um snapshot capturado pela CLI pode ser carregado em PHP com SnapshotStore::load(), e vice-versa, desde que ambos usem o mesmo diretório.