Riferimento CLI
merql include una CLI per acquisire snapshot, calcolare differenze ed eseguire fusioni direttamente dal terminale. Composer la installa come vendor/bin/merql; in una copia del repository merql si trova in bin/merql.
vendor/bin/merql funziona anche quando viene installato come dipendenza, poiché merql 0.4.1. Le versioni precedenti cercavano l'autoloader Composer solo nella directory vendor/ del pacchetto e non funzionavano quando merql era installato come dipendenza.
Avvio rapido
# 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
Una fusione a tre vie richiede che ours e theirs siano acquisiti da due database divergenti rispetto a base. Indicate a MERQL_DB_DSN il database corretto per ogni 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
Acquisire tutti e tre gli snapshot dallo stesso database, uno dopo l'altro, non funziona come fusione: theirs includerebbe già le modifiche di ours, quindi ogni riga inserita da ours verrebbe segnalata come conflitto insert_insert.
Variabili d'ambiente
CLI legge i dettagli di connessione al database dalle variabili di ambiente. Potete connettervi usando una stringa DSN PDO oppure parametri MySQL individuali.
Connessione basata su DSN
Usate MERQL_DB_DSN per le connessioni basate su PDO. È l'approccio consigliato per SQLite e per le configurazioni non standard. Il DSN deve puntare a un database MySQL o SQLite: CLI non può registrare driver per altri motori.
| Variabile | Descrizione | Esempio |
|---|---|---|
MERQL_DB_DSN |
Stringa DSN PDO completa | sqlite:/path/to/db.sqlite |
MERQL_DB_USER |
Nome utente (facoltativo con DSN) | root |
MERQL_DB_PASS |
Password (facoltativa con 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"
Usate un database SQLite basato su file. Ogni comando CLI viene eseguito in un processo separato, quindi sqlite::memory: apre sempre un nuovo database vuoto e il relativo snapshot non contiene tabelle.
Forma abbreviata di MySQL
Se MERQL_DB_DSN non è impostata, CLI usa come fallback le variabili specifiche di MySQL.
| Variabile | Predefinito | Descrizione |
|---|---|---|
MERQL_DB_NAME |
(obbligatorio) | Nome del database |
MERQL_DB_HOST |
127.0.0.1 |
Host MySQL |
MERQL_DB_PORT |
3306 |
Porta MySQL |
MERQL_DB_USER |
root |
Nome utente MySQL |
MERQL_DB_PASS |
(vuota) | Password MySQL |
MERQL_DB_ADAPTER |
pdo |
Impostate su mysqli per usare l'adapter 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"
Comandi
merql snapshot <name>
Acquisite lo stato attuale del database indicato dalle variabili di ambiente e salvatelo come snapshot con nome. È l'unico comando che si connette a un database.
vendor/bin/merql snapshot baseline
Output:
Snapshot 'baseline' saved
Tables: posts, comments, users, settings
Gli snapshot vengono salvati come file JSON in .merql/snapshots/ nella directory di lavoro (vedere Archiviazione degli snapshot). Il nome può contenere solo caratteri alfanumerici, trattini e trattini bassi.
Flusso di lavoro tipico: acquisite uno snapshot prima di apportare modifiche e un altro dopo. I due snapshot costituiscono la base per un confronto o una fusione.
merql diff <base> <current>
Confrontate due snapshot con nome e visualizzate un riepilogo delle differenze.
vendor/bin/merql diff baseline current
Output:
Changeset: baseline -> current
Inserts: 3
Updates: 7
Deletes: 1
Entrambi gli snapshot devono già esistere (acquisiti in precedenza con merql snapshot). Il confronto non richiede una connessione al database, perché opera sui file di snapshot salvati.
merql merge <base> <ours> <theirs>
Eseguite una fusione a tre vie di tre snapshot con nome.
vendor/bin/merql merge base ours theirs
Output:
Merge: base + ours + theirs
Operations: 12
Conflicts: 0
Clean: yes
Tutti e tre gli snapshot devono già esistere. La fusione non richiede una connessione al database, perché opera sui file di snapshot salvati, e non scrive mai in un database: la CLI non dispone di un comando apply. Usate PHP API per applicare il risultato della fusione.
CLI esegue fusioni a livello di colonna. Non applica fusioni a livello di cella alle colonne TEXT o JSON, quindi in questo caso due modifiche diverse alla stessa colonna sono sempre un conflitto (#7). Per le fusioni a livello di cella, usate ThreeWayMerge con un CellMergeConfig in PHP.
--dry-run
Aggiungete il flag --dry-run per visualizzare in anteprima le istruzioni SQL che la fusione genererebbe, senza eseguire nulla. Le istruzioni descrivono come trasformare lo stato base nel risultato della fusione, quindi includono le modifiche di entrambi i lati.
vendor/bin/merql merge base ours theirs --dry-run
Output:
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';
Comandi di sviluppo
Una copia del repository merql include altri script in bin/ per la suite di test guidata dall'oracolo. Non fanno parte del pacchetto Composer, quindi un'installazione come dipendenza include solo vendor/bin/merql. Eseguiteli dalla radice del repository dopo composer install.
| Comando | Descrizione |
|---|---|
./bin/oracle <name> |
Calcola il risultato di fusione atteso per uno scenario |
./bin/actual <name> |
Esegue merql su uno scenario e acquisisce l'output |
./bin/compare <name> |
Confronta l'output effettivo con quello dell'oracolo |
./bin/test-scenario <name> |
Flusso completo: configurazione, oracolo, risultati effettivi, confronto |
./bin/test-regression |
Esegue tutti gli scenari |
./bin/test-regression --category clean |
Esegue una categoria: clean, conflict, identity, types, scale o edge |
./bin/test-regression --fast |
Solo esito positivo o negativo, senza rapporti |
./bin/verify-compliance |
Rapporto completo sulla conformità |
./bin/verify-all |
PHPStan + stile del codice + PHPUnit + regressione dell'oracolo |
bin/test-regression accetta anche --jobs, ma al momento ignora il valore ed esegue gli scenari uno dopo l'altro (#5). Un --category sconosciuto stampa No scenarios found e termina correttamente.
Per la struttura degli scenari, consultate Strategia di test.
Codici di uscita
merql snapshot, diff e merge terminano con codice 1 se manca un argomento; anche snapshot lo fa se non è configurata alcuna connessione. Se manca uno snapshot, il comando termina con un'SnapshotException non gestita e un codice diverso da zero. Un comando sconosciuto stampa Unknown command, ma al momento termina con codice 0 (#3).
Archiviazione degli snapshot
Gli snapshot vengono archiviati in .merql/snapshots/ rispetto alla directory di lavoro. Ogni snapshot è un singolo file JSON denominato <name>.json. Eseguite tutti i comandi dalla stessa directory affinché trovino gli snapshot creati dagli altri comandi.
La CLI non offre opzioni né variabili di ambiente per usare un'altra posizione (#8). Per usarne una, spostatevi in un'altra directory di lavoro prima di avviarla. In PHP, impostate la directory prima di acquisire o caricare gli snapshot:
use Merql\Snapshot\SnapshotStore;
SnapshotStore::setDirectory('/var/data/merql-snapshots');
I file snapshot sono portabili. Potete copiarli tra macchine, aggiungerli al controllo versione o condividerli per il debugging collaborativo. Uno snapshot acquisito da CLI può essere caricato in PHP con SnapshotStore::load(), e viceversa, purché entrambi usino la stessa directory.