Skip to content
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
9 changes: 8 additions & 1 deletion deployer/dev/task/dump.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@
$dbSyncToolOriginPath = str_replace('<feature>', $target, get('dev_db_sync_tool_origin_path'));
$additionalOptions = "--origin-path $dbSyncToolOriginPath";

$dbSyncTool = requireSyncTool('dump');

// php-sync-tool has no -kd/-dn equivalent yet (konradmichalik/php-sync-tool#33); until it
// does, the dump lands wherever the project's own sync-tool YAML config's "dump_dir" says,
// not necessarily $dbDumpDir
$dumpLocationOptions = usingPhpSyncTool($dbSyncTool) ? '' : "-kd $dbDumpDir -dn $dbDumpFilename";

$dbSyncToolConfigPath = get('dev_db_sync_tool_config_path');
runLocally("db_sync_tool -f $dbSyncToolConfigPath/$dbSyncToolSync -y -kd $dbDumpDir -dn $dbDumpFilename $additionalOptions", ['real_time_output' => true]);
runLocally(escapeshellarg($dbSyncTool) . " -f $dbSyncToolConfigPath/$dbSyncToolSync -y $dumpLocationOptions $additionalOptions", ['real_time_output' => true]);
})
->desc('Sync database with drush');
4 changes: 3 additions & 1 deletion deployer/dev/task/import.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

$dbSyncToolSync = get('dev_db_sync_tool_default_sync');

$dbSyncTool = requireSyncTool('import');

$dbSyncToolConfigPath = get('dev_db_sync_tool_config_path');
runLocally("db_sync_tool -f $dbSyncToolConfigPath/$dbSyncToolSync -y -i $dbDumpDir/$dbDumpFilename.sql", ['real_time_output' => true]);
runLocally(escapeshellarg($dbSyncTool) . " -f $dbSyncToolConfigPath/$dbSyncToolSync -y -i $dbDumpDir/$dbDumpFilename.sql", ['real_time_output' => true]);
})
->desc('Sync database with drush');
4 changes: 3 additions & 1 deletion deployer/dev/task/sync.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@

info("sync database from remote: $target");

$dbSyncTool = requireSyncTool('sync');

$dbSyncToolConfigPath = get('dev_db_sync_tool_config_path');
runLocally("db_sync_tool -f $dbSyncToolConfigPath/$dbSyncToolSync -y $additionalOptions", ['real_time_output' => true]);
runLocally(escapeshellarg($dbSyncTool) . " -f $dbSyncToolConfigPath/$dbSyncToolSync -y $additionalOptions", ['real_time_output' => true]);
info("💽 Database from $target synced successfully");
})
->desc('Sync database with db-sync-tool');
10 changes: 8 additions & 2 deletions deployer/feature/config/set.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,14 @@
* Feature Sync
*/
#set('feature_sync_config', null);
set('db_sync_tool', 'db_sync_tool'); # set to false, to disable db sync
set('file_sync_tool', 'file_sync_tool'); # set to false, to disable file sync
// resolves to vendor/bin/sync-tool (php-sync-tool) when available locally, falling back
// to the legacy db_sync_tool PATH binary; set to false, to disable db sync
set('db_sync_tool', function () {
return resolveSyncTool('db_sync_tool');
});
// legacy-only: php-sync-tool syncs files via --with-files on the db_sync_tool call above,
// so this is unused once db_sync_tool resolves to it; set to false, to disable file sync
set('file_sync_tool', 'file_sync_tool');


set('feature_sync_target_path', null);
Expand Down
37 changes: 23 additions & 14 deletions deployer/feature/task/feature_sync.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,35 +120,44 @@ function resolveDatabaseHostToIp(string $hostname): void
$optionalVerbose = isVerbose() ? '-v' : '';

/*
* db_sync_tool
* db_sync_tool / php-sync-tool
* https://github.com/jackd248/db-sync-tool
* https://github.com/konradmichalik/php-sync-tool
*/
if (get('db_sync_tool') !== false) {
if (commandExistLocally("{{db_sync_tool}}")) {
$dbSyncTool = get('db_sync_tool');
$isPhpSyncTool = false !== $dbSyncTool && usingPhpSyncTool($dbSyncTool);

if (false !== $dbSyncTool) {
if (syncToolAvailableLocally($dbSyncTool)) {
$useRsync = $isPhpSyncTool ? '' : '--use-rsync';
// php-sync-tool has file sync integrated, no separate file_sync_tool call needed
$withFiles = $isPhpSyncTool && false !== get('file_sync_tool') ? '--with-files' : '';
Comment thread
coderabbitai[bot] marked this conversation as resolved.
info('Synching database');
runLocally("{{db_sync_tool}} -f {{feature_sync_config}} --target-path {{feature_sync_target_path}} --use-rsync -y $optionalVerbose");
runLocally(escapeshellarg($dbSyncTool) . " -f {{feature_sync_config}} --target-path {{feature_sync_target_path}} $useRsync $withFiles -y $optionalVerbose");
$synced = true;
Comment thread
konradmichalik marked this conversation as resolved.
} else {
debug("Skipping database sync, command \”{{db_sync_tool}}\” not available");
debug("Skipping database sync, command \”$dbSyncTool\” not available");
}
} else {
debug("Skipping database sync, db_sync_tool was disabled");
}

/*
* file_sync_tool
* file_sync_tool (legacy only, see above)
* https://github.com/jackd248/file-sync-tool
*/
if (get('file_sync_tool') !== false) {
if (commandExistLocally("{{file_sync_tool}}")) {
info('Synching files');
runLocally("{{file_sync_tool}} -f {{feature_sync_config}} --files-target {{feature_sync_target_path_files}} $optionalVerbose");
$synced = true;
if (!$isPhpSyncTool) {
if (get('file_sync_tool') !== false) {
if (commandExistLocally("{{file_sync_tool}}")) {
info('Synching files');
runLocally("{{file_sync_tool}} -f {{feature_sync_config}} --files-target {{feature_sync_target_path_files}} $optionalVerbose");
$synced = true;
} else {
debug("Skipping file sync, command \”{{file_sync_tool}}\” not available");
}
} else {
debug("Skipping file sync, command \”{{file_sync_tool}}\” not available");
debug("Skipping file sync, file_sync_tool was disabled");
}
} else {
debug("Skipping file sync, file_sync_tool was disabled");
}

if ($synced) info("feature branch <fg=magenta;options=bold>$feature</> was successfully synced");
Expand Down
68 changes: 68 additions & 0 deletions deployer/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,74 @@ function commandExistLocally(string $command): bool
return testLocally("hash $command 2>/dev/null");
}

/**
* Checks whether a local path is executable. Unlike commandExistLocally()/hash (built
* for PATH lookups), this reliably resolves a relative path containing a slash, e.g.
* vendor/bin/sync-tool.
*/
function isExecutableLocally(string $path): bool
{
return testLocally('[ -x ' . escapeshellarg($path) . ' ]');
}

/**
* Resolves the sync tool binary to use: prefers the Composer-installed php-sync-tool
* (https://github.com/konradmichalik/php-sync-tool) when present locally, falling back
* to the legacy PATH-installed Python tool (db-sync-tool/file-sync-tool) otherwise.
*
* Lets each downstream project migrate independently by running
* `composer require --dev konradmichalik/php-sync-tool` - no deploy.php opt-in needed.
*/
function resolveSyncTool(string $legacyBinary, string $phpBinary = 'vendor/bin/sync-tool'): string
{
return isExecutableLocally($phpBinary) ? $phpBinary : $legacyBinary;
}

/**
* Whether a resolved sync tool binary is php-sync-tool rather than the legacy tool.
* Compared against the known php-sync-tool path, not path-shape - a downstream
* project's legacy binary can itself be configured as an absolute or relative path,
* which would otherwise be misclassified.
*/
function usingPhpSyncTool(string $resolvedBinary, string $phpBinary = 'vendor/bin/sync-tool'): bool
{
return $resolvedBinary === $phpBinary;
}

/**
* Checks whether a resolved sync tool binary is actually available locally: a path
* (containing a slash) via isExecutableLocally(), a bare PATH command via
* commandExistLocally().
*/
function syncToolAvailableLocally(string $binary): bool
{
return str_contains($binary, '/')
? isExecutableLocally($binary)
: commandExistLocally($binary);
}

/**
* Resolves the sync tool binary and verifies it is actually available locally, or
* throws. Used by the dev:* tasks, which have no "disabled" concept and must hard-fail
* rather than silently skip when the tool is missing.
*
* @throws \RuntimeException if db_sync_tool was disabled or is not available locally
*/
function requireSyncTool(string $action): string
{
$dbSyncTool = get('db_sync_tool');

if (false === $dbSyncTool) {
throw new \RuntimeException("db_sync_tool was disabled, cannot $action.");
}

if (!syncToolAvailableLocally($dbSyncTool)) {
throw new \RuntimeException("Sync tool \"$dbSyncTool\" not available locally.");
}

return $dbSyncTool;
}

/**
* Runs a remote command with the possibility to overwrite the default command options
*/
Expand Down
6 changes: 5 additions & 1 deletion deployer/sync/config/set.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@

namespace Deployer;

set('db_sync_tool', 'db_sync_tool'); # set to false, to disable db backup
// resolves to vendor/bin/sync-tool (php-sync-tool) when available locally, falling back
// to the legacy db_sync_tool PATH binary; set to false, to disable db backup
set('db_sync_tool', function () {
return resolveSyncTool('db_sync_tool');
});
#set('sync_database_backup_config', null);
11 changes: 7 additions & 4 deletions deployer/sync/task/database_backup.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@

$optionalVerbose = isVerbose() ? '-v' : '';

if (false === get('db_sync_tool')) {
$dbSyncTool = get('db_sync_tool');

if (false === $dbSyncTool) {
debug('Skipping database backup, db_sync_tool was disabled');
return;
}

if (commandExistLocally("{{db_sync_tool}}")) {
if (syncToolAvailableLocally($dbSyncTool)) {
$useRsync = usingPhpSyncTool($dbSyncTool) ? '' : '--use-rsync';
info('Generating a database backup');
runLocally("{{db_sync_tool}} -f {{sync_database_backup_config}} --use-rsync -y $optionalVerbose");
runLocally(escapeshellarg($dbSyncTool) . " -f {{sync_database_backup_config}} $useRsync -y $optionalVerbose");
} else {
Comment thread
konradmichalik marked this conversation as resolved.
debug("Skipping database backup, {{db_sync_tool}} not available");
debug("Skipping database backup, $dbSyncTool not available");
}

})
Expand Down
8 changes: 7 additions & 1 deletion docs/FEATURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ labels:
type: feature-branch-deployment
```

For using the [synchronization](#synchronization), you need to have the following pip packages installed:
For using the [synchronization](#synchronization), you need a sync tool installed. The preferred, Composer-native option is [php-sync-tool](https://github.com/konradmichalik/php-sync-tool):

```bash
$ composer require --dev konradmichalik/php-sync-tool
```

It is auto-detected at `vendor/bin/sync-tool` and used automatically once installed, no `deploy.php` change needed. The legacy Python tools remain supported as a fallback for projects that have not migrated yet:

```bash
$ pip3 install db-sync-tool-kmi file-sync-tool-kmi
Expand Down