Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
376798ffb7
|
|||
b6c204a08d
|
|||
b3092e0bee
|
|||
64de601728
|
|||
e1de358e91
|
|||
1a3508d765
|
|||
05b7443a3a
|
|||
d98a79efce | |||
bbc379b70b
|
|||
7deab9c67f
|
18
CHANGELOG.md
Normal file
18
CHANGELOG.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Changelog
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [unreleased](https://git.d3data.de/D3Public/OXID-Deployer/compare/1.0.0.0...rel_1.x)
|
||||||
|
|
||||||
|
## [1.0.0.0](https://git.d3data.de/D3Public/OXID-Deployer/releases/tag/1.0.0.0) - 2024-11-03
|
||||||
|
### Added
|
||||||
|
- initial implementation
|
||||||
|
- OXID base recipe
|
||||||
|
- additional shop depend deployment tasks
|
||||||
|
- additional task
|
||||||
|
- show OXID version
|
||||||
|
- create backup
|
||||||
|
- clone database
|
||||||
|
- run migrations
|
17
README.md
17
README.md
@ -6,11 +6,18 @@ The recipe can usually also be used for projects based on OXID 6.4 and 6.5.
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
See Deployer OXID recipe project for further instructions.
|
See [Deployer OXID recipe project](https://packagist.org/packages/d3/oxid-deployer-project) for further instructions.
|
||||||
|
|
||||||
## available tasks
|
## available tasks
|
||||||
|
|
||||||
- dep `shop:getVersion` [stage] - show version of current OXID installation
|
### OXID
|
||||||
- dep `shop:cloneDatabase` [stage] - dump contents from source to destination database
|
- dep `oxid:getVersion` [stage] - show version of current OXID installation
|
||||||
- dep `shop:runMigration` [stage] - run all database migrations
|
- dep `oxid:cloneDatabase` [stage] - dump contents from source to destination database
|
||||||
- dep `setup:createDbConfig` [stage] - generate database configuration file
|
- dep `oxid:runMigration` [stage] - run all database migrations
|
||||||
|
|
||||||
|
### database
|
||||||
|
- dep `database:createBackup` [stage] - rotate old database backups and create a new one
|
||||||
|
- dep `database:clone` [stage] - dump contents from source to destination database
|
||||||
|
|
||||||
|
### setup
|
||||||
|
- dep `setup:createDbConfig` [stage] - generate database configuration file
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "d3/oxid-deployer",
|
"name": "d3/oxid-deployer",
|
||||||
"description": "Deployer recipe for OXID eShop",
|
"description": "Deployer recipe for OXID eShop",
|
||||||
|
"keywords": [
|
||||||
|
"deployer",
|
||||||
|
"deployment",
|
||||||
|
"recipe",
|
||||||
|
"OXID",
|
||||||
|
"eShop",
|
||||||
|
"d3"
|
||||||
|
],
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://d3data.de/",
|
"homepage": "https://d3data.de/",
|
||||||
|
51
recipe/databaseTasks.php
Normal file
51
recipe/databaseTasks.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Deployer;
|
||||||
|
|
||||||
|
require_once 'inc/database.php';
|
||||||
|
|
||||||
|
desc('dump contents from source to destination database');
|
||||||
|
task('database:clone', function () {
|
||||||
|
if (get('mysql_configured') && get('mysqldump_configured')) {
|
||||||
|
info('Note: Use a dedicated read only user for accessing the source database.');
|
||||||
|
info('Using the following source database:');
|
||||||
|
$source_host = ask('source database host', 'localhost');
|
||||||
|
$source_port = ask('source database port', '3306');
|
||||||
|
$source_name = ask('source database name');
|
||||||
|
$source_user = ask('source database user');
|
||||||
|
$source_pass = askHiddenResponse('source database password');
|
||||||
|
$target_name = parse_ini_file(get('db_conf_path'))['database'];
|
||||||
|
if (askConfirmation('Do you really want to clone from "'.$source_name.'" to "'.$target_name.'"? The target database "'.$target_name.'" will be overwritten!')) {
|
||||||
|
info('cloning database');
|
||||||
|
$auth = "-h".$source_host." -P".$source_port." -u".$source_user." -p'".$source_pass."'";
|
||||||
|
run("{{bin/mysqldump}} ".$auth." --opt --no-create-db -f ".$source_name." $({{bin/mysql}} ".$auth." -ANe\"SET group_concat_max_len = 10485760; SELECT GROUP_CONCAT(table_name SEPARATOR ' ') FROM information_schema.tables WHERE table_schema='".$source_name."' AND engine IS NOT NULL;\") | {{bin/mysql}} --defaults-extra-file={{db_conf_path}} -f");
|
||||||
|
info('creating views');
|
||||||
|
run('{{release_or_current_path}}/vendor/bin/oe-eshop-db_views_regenerate');
|
||||||
|
info('successfully finished');
|
||||||
|
} else {
|
||||||
|
info('abborted');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warning('missing config, task skipped');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
desc('rotate old database backups and create a new one');
|
||||||
|
task('database:createBackup', function () {
|
||||||
|
if (get('mysql_configured') && get('mysqldump_configured')) {
|
||||||
|
if (!test("[ -f {{deploy_path}}/database/rotatemap.conf ]")) {
|
||||||
|
run('printf "{{deploy_path}}/database/backup/backup.sql {\n rotate 5\n}" > {{deploy_path}}/database/rotatemap.conf');
|
||||||
|
}
|
||||||
|
if (!test("[ -d {{deploy_path}}/database/backup ]")) {
|
||||||
|
run("mkdir -p {{deploy_path}}/database/backup");
|
||||||
|
}
|
||||||
|
$source_name = parse_ini_file(get('db_conf_path'))['database'];
|
||||||
|
if (test("[ -f {{deploy_path}}/database/backup/backup.sql ]")) {
|
||||||
|
run("logrotate -f -s {{deploy_path}}/database/rotatemap.state {{deploy_path}}/database/rotatemap.conf");
|
||||||
|
}
|
||||||
|
run("{{bin/mysqldump}} --defaults-extra-file={{db_conf_path}} --opt --no-create-db -f ".$source_name." $({{bin/mysql}} --defaults-extra-file={{db_conf_path}} -ANe\"SET group_concat_max_len = 10485760; SELECT GROUP_CONCAT(table_name SEPARATOR ' ') FROM information_schema.tables WHERE table_schema='".$source_name."' AND engine IS NOT NULL;\") > {{deploy_path}}/database/backup/backup.sql");
|
||||||
|
info('successfully dumped to {{deploy_path}}/database/backup/backup.sql');
|
||||||
|
} else {
|
||||||
|
warning('missing config, task skipped');
|
||||||
|
}
|
||||||
|
});
|
21
recipe/inc/database.php
Normal file
21
recipe/inc/database.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Deployer;
|
||||||
|
|
||||||
|
set('db_conf_path', function () {
|
||||||
|
return '{{deploy_path}}/database/.my.cnf';
|
||||||
|
});
|
||||||
|
|
||||||
|
set('database_configured', function() {
|
||||||
|
return has('db_conf_path') && strlen(get('db_conf_path')) && test("[ -f {{db_conf_path}} ]");
|
||||||
|
});
|
||||||
|
|
||||||
|
set('mysql_configured', function() {
|
||||||
|
return has('bin/mysql') && strlen(get('bin/mysql')) &&
|
||||||
|
get('database_configured');
|
||||||
|
});
|
||||||
|
|
||||||
|
set('mysqldump_configured', function() {
|
||||||
|
return has('bin/mysql') && strlen(get('bin/mysql')) &&
|
||||||
|
get('database_configured');
|
||||||
|
});
|
27
recipe/menu.php
Normal file
27
recipe/menu.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Deployer;
|
||||||
|
|
||||||
|
task('logs:access')->hidden();
|
||||||
|
task('logs:app')->hidden();
|
||||||
|
task('logs:caddy')->hidden();
|
||||||
|
task('logs:php-fpm')->hidden();
|
||||||
|
task('provision:check')->hidden();
|
||||||
|
task('provision:composer')->hidden();
|
||||||
|
task('provision:configure')->hidden();
|
||||||
|
task('provision:databases')->hidden();
|
||||||
|
task('provision:firewall')->hidden();
|
||||||
|
task('provision:install')->hidden();
|
||||||
|
task('provision:mariadb')->hidden();
|
||||||
|
task('provision:mysql')->hidden();
|
||||||
|
task('provision:node')->hidden();
|
||||||
|
task('provision:php')->hidden();
|
||||||
|
task('provision:postgresql')->hidden();
|
||||||
|
task('provision:server')->hidden();
|
||||||
|
task('provision:ssh')->hidden();
|
||||||
|
task('provision:ssh_copy_id')->hidden();
|
||||||
|
task('provision:update')->hidden();
|
||||||
|
task('provision:upgrade')->hidden();
|
||||||
|
task('provision:user')->hidden();
|
||||||
|
task('provision:verify')->hidden();
|
||||||
|
task('provision:website')->hidden();
|
@ -4,7 +4,9 @@ namespace Deployer;
|
|||||||
|
|
||||||
require_once __DIR__.'/../../../deployer/deployer/recipe/composer.php';
|
require_once __DIR__.'/../../../deployer/deployer/recipe/composer.php';
|
||||||
|
|
||||||
|
require_once __DIR__.'/menu.php';
|
||||||
require_once __DIR__.'/hooks.php';
|
require_once __DIR__.'/hooks.php';
|
||||||
|
require_once __DIR__.'/databaseTasks.php';
|
||||||
require_once __DIR__.'/deployTasks.php';
|
require_once __DIR__.'/deployTasks.php';
|
||||||
require_once __DIR__.'/setupTasks.php';
|
require_once __DIR__.'/setupTasks.php';
|
||||||
require_once __DIR__.'/shopTasks.php';
|
require_once __DIR__.'/shopTasks.php';
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Deployer;
|
namespace Deployer;
|
||||||
|
|
||||||
|
require_once 'inc/database.php';
|
||||||
|
|
||||||
desc('create database coniguration file');
|
desc('create database coniguration file');
|
||||||
task('setup:createDbConfig', function () {
|
task('setup:createDbConfig', function () {
|
||||||
try {
|
try {
|
||||||
@ -20,9 +22,10 @@ task('setup:createDbConfig', function () {
|
|||||||
if (test("[ -f {{db_conf_path}} ]")) {
|
if (test("[ -f {{db_conf_path}} ]")) {
|
||||||
$db_host = ask('database host', 'localhost');
|
$db_host = ask('database host', 'localhost');
|
||||||
$db_port = ask('database port', '3306');
|
$db_port = ask('database port', '3306');
|
||||||
|
$db_name = ask('database name');
|
||||||
$db_user = ask('database user');
|
$db_user = ask('database user');
|
||||||
$db_pass = askHiddenResponse('database password');
|
$db_pass = askHiddenResponse('database password');
|
||||||
run('printf "[mysql]\nuser='.$db_user.'\npassword=\"'.$db_pass.'\"\nhost='.$db_host.'\nport='.$db_port.'\n\n[mysqldump]\nuser='.$db_user.'\npassword=\"'.$db_pass.'\"\nhost='.$db_host.'\nport='.$db_port.'" > {{db_conf_path}}');
|
run('printf "[client]\nuser='.$db_user.'\npassword=\"'.$db_pass.'\"\nhost='.$db_host.'\nport='.$db_port.'\n\n[mysql]\ndatabase=\"'.$db_name.'\"" > {{db_conf_path}}');
|
||||||
info('config successful created');
|
info('config successful created');
|
||||||
} else {
|
} else {
|
||||||
throw new \RuntimeException('can not create {{db_conf_path}}, task stopped');
|
throw new \RuntimeException('can not create {{db_conf_path}}, task stopped');
|
||||||
@ -30,4 +33,4 @@ task('setup:createDbConfig', function () {
|
|||||||
} catch(\RuntimeException $e) {
|
} catch(\RuntimeException $e) {
|
||||||
warning($e->getMessage());
|
warning($e->getMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -3,53 +3,49 @@
|
|||||||
namespace Deployer;
|
namespace Deployer;
|
||||||
|
|
||||||
desc('run all database migrations');
|
desc('run all database migrations');
|
||||||
task('shop:runMigration', [
|
task('oxid:runMigration', [
|
||||||
'shop:setShopsOffline',
|
'oxid:setShopsOffline',
|
||||||
'shop:executeMigrations',
|
'oxid:executeMigrations',
|
||||||
'shop:setShopsOnline'
|
'oxid:setShopsOnline'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
require_once 'inc/database.php';
|
||||||
|
|
||||||
desc('set shops offline');
|
desc('set shops offline');
|
||||||
task('shop:setShopsOffline', function() {
|
task('oxid:setShopsOffline', function() {
|
||||||
if (has('bin/mysql') && strlen(get('bin/mysql')) &&
|
if (get('mysql_configured')) {
|
||||||
has('db_name') && strlen(get('db_name')) &&
|
|
||||||
has('db_conf_path') && strlen(get('db_conf_path')) && test("[ -f {{db_conf_path}} ]")
|
|
||||||
) {
|
|
||||||
$query = "UPDATE oxshops SET oxactive = '0', OXREGISTERSUBJECT = CONCAT('..', OXREGISTERSUBJECT) WHERE oxactive = '1';";
|
$query = "UPDATE oxshops SET oxactive = '0', OXREGISTERSUBJECT = CONCAT('..', OXREGISTERSUBJECT) WHERE oxactive = '1';";
|
||||||
run('{{bin/mysql}} --defaults-extra-file={{db_conf_path}} {{db_name}} -e "'.$query.'"');
|
run('{{bin/mysql}} --defaults-extra-file={{db_conf_path}} -e "'.$query.'"');
|
||||||
} else {
|
} else {
|
||||||
warning('missing config, task skipped');
|
warning('missing config, task skipped');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
task('shop:runMigration:failed', function() {
|
task('oxid:runMigration:failed', function() {
|
||||||
invoke('shop:setShopsOnline');
|
invoke('oxid:setShopsOnline');
|
||||||
})->hidden();
|
})->hidden();
|
||||||
|
|
||||||
fail('shop:runMigration', 'shop:runMigration:failed');
|
fail('oxid:runMigration', 'oxid:runMigration:failed');
|
||||||
|
|
||||||
desc('execute OXID Doctrine migrations');
|
desc('execute OXID Doctrine migrations');
|
||||||
task('shop:executeMigrations', function () {
|
task('oxid:executeMigrations', function () {
|
||||||
if (test("[ -f {{current_path}}/vendor/bin/oe-eshop-doctrine_migration ]")) {
|
if (test("[ -f {{current_path}}/vendor/bin/oe-eshop-doctrine_migration ]")) {
|
||||||
run('{{bin/php}} {{current_path}}/vendor/bin/oe-eshop-doctrine_migration migrations:migrate');
|
run('{{bin/php}} {{current_path}}/vendor/bin/oe-eshop-doctrine_migration migrations:migrate');
|
||||||
}
|
}
|
||||||
})->hidden();;
|
})->hidden();;
|
||||||
|
|
||||||
desc('set shops online');
|
desc('set shops online');
|
||||||
task('shop:setShopsOnline', function() {
|
task('oxid:setShopsOnline', function() {
|
||||||
if (has('bin/mysql') && strlen(get('bin/mysql')) &&
|
if (get('mysql_configured')) {
|
||||||
has('db_name') && strlen(get('db_name')) &&
|
|
||||||
has('db_conf_path') && strlen(get('db_conf_path')) && test("[ -f {{db_conf_path}} ]")
|
|
||||||
) {
|
|
||||||
$query = "UPDATE oxshops SET oxactive = '1', OXREGISTERSUBJECT = SUBSTR(OXREGISTERSUBJECT, 3) WHERE oxactive = '0' AND OXREGISTERSUBJECT LIKE '..%';";
|
$query = "UPDATE oxshops SET oxactive = '1', OXREGISTERSUBJECT = SUBSTR(OXREGISTERSUBJECT, 3) WHERE oxactive = '0' AND OXREGISTERSUBJECT LIKE '..%';";
|
||||||
run('{{bin/mysql}} --defaults-extra-file={{db_conf_path}} {{db_name}} -e "'.$query.'"');
|
run('{{bin/mysql}} --defaults-extra-file={{db_conf_path}} -e "'.$query.'"');
|
||||||
} else {
|
} else {
|
||||||
warning('missing config, task skipped');
|
warning('missing config, task skipped');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
desc('show version of current OXID installation');
|
desc('show version of current OXID installation');
|
||||||
task('shop:getVersion', function () {
|
task('oxid:getVersion', function () {
|
||||||
if (test("[ -f {{current_path}}/composer.lock ]")) {
|
if (test("[ -f {{current_path}}/composer.lock ]")) {
|
||||||
cd('{{current_path}}');
|
cd('{{current_path}}');
|
||||||
info(
|
info(
|
||||||
@ -61,30 +57,6 @@ task('shop:getVersion', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
desc('dump contents from source to destination database');
|
desc('dump contents from source to destination database');
|
||||||
task('shop:cloneDatabase', function () {
|
task('oxid:cloneDatabase', function () {
|
||||||
if (has('bin/mysql') && strlen(get('bin/mysql')) &&
|
invoke('database:clone');
|
||||||
has('bin/mysqldump') && strlen(get('bin/mysqldump')) &&
|
|
||||||
has('db_name') && strlen(get('db_name')) &&
|
|
||||||
has('db_conf_path') && strlen(get('db_conf_path')) && test("[ -f {{db_conf_path}} ]")
|
|
||||||
) {
|
|
||||||
info('Note: Use a dedicated read only user for accessing the source database.');
|
|
||||||
info('Using the following source database:');
|
|
||||||
$source_host = ask('source database host', 'localhost');
|
|
||||||
$source_port = ask('source database port', '3306');
|
|
||||||
$source_name = ask('source database name');
|
|
||||||
$source_user = ask('source database user');
|
|
||||||
$source_pass = askHiddenResponse('source database password');
|
|
||||||
if (askConfirmation('Do you really want to clone from "'.$source_name.'" to "{{db_name}}"? The target database "{{db_name}}" will be overwritten!')) {
|
|
||||||
info('cloning database');
|
|
||||||
$auth = "-h".$source_host." -P".$source_port." -u".$source_user." -p'".$source_pass."'";
|
|
||||||
run("{{bin/mysqldump}} ".$auth." --opt --no-create-db -f ".$source_name." $({{bin/mysql}} ".$auth." -ANe\"SET group_concat_max_len = 10485760; SELECT GROUP_CONCAT(table_name SEPARATOR ' ') FROM information_schema.tables WHERE table_schema='".$source_name."' AND engine IS NOT NULL;\") | {{bin/mysql}} --defaults-extra-file={{db_conf_path}} -f {{db_name}}");
|
|
||||||
info('creating views');
|
|
||||||
run('{{release_or_current_path}}/vendor/bin/oe-eshop-db_views_regenerate');
|
|
||||||
info('successfully finished');
|
|
||||||
} else {
|
|
||||||
info('abborted');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
warning('missing config, task skipped');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user