Skip to content

Commit

Permalink
Create .env.deployer for configuration. Update Readme
Browse files Browse the repository at this point in the history
  • Loading branch information
mmoollllee committed Feb 5, 2023
1 parent f933c56 commit e4f3c5a
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 147 deletions.
30 changes: 21 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

Trellis provides a powerful deployment with Ansible. But if you would like to deploy Bedrock only while running a custom process, Deployer is a quick and simple alternative.

Maybe you are even trying to deploy Bedrock to a shared hosting. Depending on your hosting environment, this *may* be possible. Check out [florianmoser/plesk-deployer](https://github.com/FlorianMoser/plesk-deployer).
Maybe you are even trying to deploy Bedrock to a shared hosting like Plesk. Depending on your hosting environment, this can be possible.

**A word of caution:** Make sure you have a backup of your local as well as your remote files, before experimenting with deployment recipes. Files might easily get overwritten when you provide wrong paths! You are solely responsible by using the recipes provided here.

Expand All @@ -14,13 +14,20 @@ PHP developers who would like to deploy their Bedrock applications using Deploye
Use Composer:

````
$ composer require florianmoser/bedrock-deployer
$ composer require mmoollllee/bedrock-deployer
````

Setup your Trellis & Bedrock environment and create a repository. The repository may contain a trellis and a site folder, or
the bedrock project [example](https://github.com/mmoollllee/bedrock)

Create a deploy.php in your project root and configure your environments. You might want to use [examples/deploy.full-example.php](https://github.com/mmoollllee/bedrock-deployer/blob/master/examples/deploy.full-example.php) and have a look at its required [config file]([examples/deploy.full-example.php](https://github.com/mmoollllee/bedrock-deployer/blob/master/config/config.php)). If so first run will create a `.env.deployer` and ask for your project's details.

First run with `vendor/bin/dep -vvv deploy` & select target environment.

# Recipes
This package offers several recipes to help you with your Bedrock deployment. Require each package as needed.
This package offers several recipes to help you with your Bedrock deployment. Require each package as needed or use the example configuration file in [examples/deploy.full-example.php](https://github.com/mmoollllee/bedrock-deployer/blob/master/examples/deploy.full-example.php) and have a look at its required [config file]([examples/deploy.full-example.php](https://github.com/mmoollllee/bedrock-deployer/blob/master/config/config.php)).

These are the available recipes:
The available recipes:

## Bedrock DB
Provides tasks to export the database from the server and import it to your development machine and vice versa.
Expand All @@ -37,7 +44,7 @@ Requirements:
Load into your deploy.php file with:

````php
require 'vendor/florianmoser/bedrock-deployer/recipe/bedrock_db.php';
require 'vendor/mmoollllee/bedrock-deployer/recipe/bedrock_db.php';
````

Requires these Deployer environment variables to be set:
Expand Down Expand Up @@ -207,9 +214,14 @@ Compiles the Sage assets on the local machine and then uploads them to remote se
## Trellis
You will not want to use these recipes to deploy Trellis. Trellis has its own and powerful deployment process. However you might use Trellis for developing and only use these recipes to deploy Bedrock.

The downside with this method is that you will have a /site as well as a /trellis directory in your repository. So both directories will be cloned to the server.

This task deals with this situation:
You might have a site & a trellis directory in your repository, or only the bedrock-style repository without site folder.
This task deals with both situations:

### Task trellis:remove
Will delete the remote /trellis directory and move the content of /site to /. Use this task after deployment but before symlink changes.
Will check for a /site folder. If true it will delete the remote /trellis directory and move the content of /site to /. Use this task after deployment but before symlink changes.

## Advanced Custom Fields Pro
ACF PRO is a powerful Wordpress Plugin to build userfriendly custom fields and more. The Pro version via composer install needs a auth.json for authentification. [See official documentation on how to get it's content](https://www.advancedcustomfields.com/resources/installing-acf-pro-with-composer/).

### Task bedrock:acf
Uploads your local auth.json to the release directory.
49 changes: 49 additions & 0 deletions config/config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

/**
* Holds default configuration. Copy and paste set-methods to your deploy.php to overwrite them.
*/

namespace Deployer;

require(__DIR__ . '/../../../autoload.php');

use Dotenv\Dotenv;

// .env.deployer will be generated on first run.
if (file_exists(get('local_root').'/.env.deployer')) {
$localEnv = Dotenv::createUnsafeImmutable(get('local_root'), '.env.deployer');
$localEnv->load();
}

require __DIR__ . '/../../../deployer/deployer/recipe/common.php';
require __DIR__ . '/../recipe/recipes.php';

// CLI Configuration
// set('bin/composer', function () { return 'composer'; });
set('bin/composer', function () { return '/opt/plesk/php/8.1/bin/php /usr/lib/plesk-9.0/composer.phar'; });
set('composer_options', 'install --verbose --no-interaction');
// Download wp-cli.phar
set('bin/wp', function () {
run("cd {{deploy_path}} && curl -sS -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar");
run('mv {{deploy_path}}/wp-cli.phar {{deploy_path}}/.dep/wp-cli.phar');
return '{{bin/php}} {{deploy_path}}/.dep/wp-cli.phar';
});

// Common Deployer config
set('keep_releases', function () { return getenv('KEEP_RELEASES'); });
set( 'repository', function () { return getenv('REPO'); });
set( 'shared_dirs', ['web/app/uploads'] );
set( 'domain', basename(get('local_root')) );

// Bedrock DB config
set( 'vagrant_dir', get('local_root') . '/../trellis' );
set( 'vagrant_root', '/srv/www/' . get('domain') . '/current' );

// Bedrock DB and Sage config
set( 'theme_path', function () { return getenv('THEME_PATH'); });

// File transfer config
set( 'sync_dirs', [
get('local_root') . '/web/app/uploads/' => '{{deploy_path}}/shared/web/app/uploads/',
] );
54 changes: 17 additions & 37 deletions examples/deploy.full-example.php
Original file line number Diff line number Diff line change
@@ -1,57 +1,36 @@
<?php

/**
* Deploy with `php vendor/bin/dep deploy stage`
* - Deploy with `php vendor/bin/dep deploy stage`
* - Set Webspace Path to 'current/web'
*/

namespace Deployer;

require 'vendor/deployer/deployer/recipe/common.php';
require 'vendor/mmoollllee/bedrock-deployer/recipe/recipes.php';
// Configurate Hostname of stage & production
$hostname = 'example.com';
$stage_hostname = $hostname;

// Configuration
set('bin/composer', function () { return '/opt/plesk/php/8.1/bin/php /usr/lib/plesk-9.0/composer.phar'; }); // set('bin/composer', function () { return 'composer'; });
set('composer_options', 'install --verbose --no-interaction');
set('bin/wp', function () {
run("cd {{deploy_path}} && curl -sS -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar");
run('mv {{deploy_path}}/wp-cli.phar {{deploy_path}}/.dep/wp-cli.phar');
return '{{bin/php}} {{deploy_path}}/.dep/wp-cli.phar';
});
// get directory of projects. Will be used for domain name,...
set( 'local_root', dirname( __FILE__ ) );

// Common Deployer config
set( 'repository', '[email protected]:example/example.git' );
set( 'shared_dirs', ['web/app/uploads'] );

// Bedrock DB config
set( 'vagrant_dir', dirname( __FILE__ ) . '/../trellis' );
set( 'vagrant_root', '/srv/www/example.com/current' );

// Bedrock DB and Sage config
set( 'local_root', dirname( __FILE__ ) );;
set( 'theme_path', 'web/app/themes/template' );

// File transfer config
set( 'sync_dirs', [
dirname( __FILE__ ) . '/web/app/uploads/' => '{{deploy_path}}/shared/web/app/uploads/',
] );

// Hosts
require 'vendor/mmoollllee/bedrock-deployer/config/config.php';

// set
host( 'stage' )
->setHostname( 'example.com' )
->set('remote_user', 'user')
->set( 'deploy_path', '~/httpdocs/deploy' );
// Set Webspace-Path to ~/stage/deploy/current/web/
->setHostname( $stage_hostname )
->set('remote_user', function () { return getenv('STAGE_USERNAME') ?: getenv('USERNAME'); })
->set('deploy_path', function () { return getenv('STAGE_DIR'); });

host( 'prod' )
->setHostname( 'example.com' )
->set('remote_user', 'user')
->set( 'deploy_path', '~/httpdocs/deploy' );

->setHostname( $hostname )
->set('remote_user', function () { return getenv('USERNAME'); })
->set('deploy_path', function () { return getenv('DIR'); });

// Tasks
desc( 'Deploy whole project' );
task( 'deploy', [
'deployer:check',
'bedrock:prepare',
'deploy:lock',
'deploy:release',
Expand All @@ -73,6 +52,7 @@

desc( 'Deploy only app' );
task( 'update', [
'deployer:check',
'bedrock:prepare',
'deploy:lock',
'deploy:release',
Expand Down
102 changes: 4 additions & 98 deletions recipe/bedrock_auth.php
Original file line number Diff line number Diff line change
@@ -1,110 +1,16 @@
<?php

/**
* Manages the Bedrock .env file on the server. If not previous
* release is available, the task asks for credentials and options,
* generates salts and stores them in a new .env file in the current
* release.
*
* If a previous release is available, the .env file is copied from
* that release to the current release.
* ACF PRO will be installed via composer (offical support: https://www.advancedcustomfields.com/resources/installing-acf-pro-with-composer/)
* and needs a `auth.json` in the project directory for authentification
*/

namespace Deployer;

/*
* Tries to copy .env file from previous release to current release.
* If not available, the .env file is created while prompting the
* user for credentials.
* Tries to copy auth.json file from previous release to current release.
* If not available, checks the presence locally and uploads auth.json.
*/
desc( 'Makes sure, .env file for Bedrock is available' );
task( 'bedrock:env', function () {

// Try to copy .env file from previous release to current release
if ( has( 'previous_release' ) ) {
if ( test( "[ -f {{previous_release}}/.env ]" ) ) {
run( "cp {{previous_release}}/.env {{release_path}}" );
return;
}
}

// If previous .env file is not available, create one

/**
* Generates a random token with a length of 64 chars.
*
* Bases on wp_generate_password() function.
*
* @return string
*/
function generate_salt() {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_ []{}<>~+=,.;:/?|';
$char_option_length = strlen( $chars ) - 1;

$password = '';
for ( $i = 0; $i < 64; $i ++ ) {
$password .= substr( $chars, random_int( 0, $char_option_length ), 1 );
}

return $password;
}

// Keys that require a salt token
$salt_keys = [
'AUTH_KEY',
'SECURE_AUTH_KEY',
'LOGGED_IN_KEY',
'NONCE_KEY',
'AUTH_SALT',
'SECURE_AUTH_SALT',
'LOGGED_IN_SALT',
'NONCE_SALT',
];

writeln( '<comment>Generating .env file</comment>' );

// Ask for credentials
$wp_domain = ask( get( 'stage' ) . ' server WordPress domain (ie domain.com)' );
$db_name = ask( get( 'stage' ) . ' server WordPress DB name' );
$db_user = ask( get( 'stage' ) . ' server WordPress DB user' );
$db_pass = askHiddenResponse( get( 'stage' ) . ' server WordPress DB password' );
$db_host = ask( get( 'stage' ) . ' server WordPress DB host', '127.0.0.1' );
$wp_env = askChoice( get( 'stage' ) . ' server ENV', ['development' => 'development', 'staging' => 'staging', 'production' => 'production'], 'staging' );
$wp_prot = askChoice( get( 'stage' ) . ' server protocol', ['http' => 'http', 'https' => 'https'], 'http' );

set('absolute_path', function () {
return run('cd {{deploy_path}} && pwd');
});
$wpcachehome = '{{absolute_path}}/current/web/app/plugins/wp-super-cache/';
$wpcachepath = '{{absolute_path}}/current/web/app/cache/';


ob_start();

echo <<<EOL
DB_NAME='{$db_name}'
DB_USER='{$db_user}'
DB_PASSWORD='{$db_pass}'
DB_HOST='{$db_host}'
WP_ENV='{$wp_env}'
WP_HOME='{$wp_prot}://{$wp_domain}'
WP_SITEURL='{$wp_prot}://{$wp_domain}/wp'
DOMAIN_CURRENT_SITE='{$wp_domain}'
PROTOCOL='{$wp_prot}'
WPCACHEHOME='{$wpcachehome}'
CACHE_PATH='{$wpcachepath}'
EOL;

foreach ( $salt_keys as $key ) {
echo $key . "='" . generate_salt() . "'" . PHP_EOL;
}

$content = ob_get_clean();

run( 'echo "' . $content . '" > {{release_path}}/.env' );
} );


desc( 'Makes sure, auth.json file for ACF PRO is available' );
task( 'bedrock:acf', function () {
Expand Down
6 changes: 3 additions & 3 deletions recipe/bedrock_env.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ function generate_salt() {
writeln( '<comment>Generating .env file</comment>' );

// Ask for credentials
$wp_domain = ask( get( 'stage' ) . ' server WordPress domain (ie domain.com)' );
$db_name = ask( get( 'stage' ) . ' server WordPress DB name' );
$db_user = ask( get( 'stage' ) . ' server WordPress DB user' );
$wp_domain = ask( get( 'stage' ) . ' server WordPress domain (ie domain.com)', get('domain') );
$db_name = ask( get( 'stage' ) . ' server WordPress DB name', $wp_domain );
$db_user = ask( get( 'stage' ) . ' server WordPress DB user', $wp_domain );
$db_pass = askHiddenResponse( get( 'stage' ) . ' server WordPress DB password' );
$db_host = ask( get( 'stage' ) . ' server WordPress DB host', '127.0.0.1' );
$wp_env = askChoice( get( 'stage' ) . ' server ENV', ['development' => 'development', 'staging' => 'staging', 'production' => 'production'], 'staging' );
Expand Down
56 changes: 56 additions & 0 deletions recipe/deployer_check.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

/**
* Check for configuration files before starting
*/

namespace Deployer;

/*
* Check for .env.deployer and if not present, create it
*/

desc( '.env.deployer present?' );
task( 'deployer:check', function () {

// Check if local .env.deployer exists
if ( testLocally('[ -f {{local_root}}/.env.deployer ]')) {
return;
}

// If not create one

writeln( '<comment>Generating .env.deployer file</comment>' );

// Ask for credentials
$repo = ask( 'Bedrock Repository' );
$prod_dir = ask( 'Production Directory', '~/httpdocs' );
$stage_dir = ask( 'Stage Directory', '~/stage.'.get('domain') );
$prod_user = ask( 'Production Username' );
$stage_user = ask( 'Stage Username', $prod_user );
$theme_name = ask( 'themes name for template_path?', 'template' );
$keep_releases = ask( 'Releases to keep', '4' );

ob_start();

echo <<<EOL
REPO='{$repo}'
DIR='{$prod_dir}'
STAGE_DIR='{$stage_dir}'
USERNAME='{$prod_user}'
STAGE_USERNAME='{$stage_user}'
THEME_PATH='web/app/themes/{$theme_name}'
KEEP_RELEASES={$keep_releases}
EOL;

$content = ob_get_clean();



runLocally( 'echo "' . $content . '" > {{local_root}}/.env.deployer' );

writeln( '<comment>Rerun task please</comment>' );
return;

} );
1 change: 1 addition & 0 deletions recipe/recipes.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

require 'vendor/mmoollllee/bedrock-deployer/recipe/prepare.php';
require 'vendor/mmoollllee/bedrock-deployer/recipe/deployer_check.php';
require 'vendor/mmoollllee/bedrock-deployer/recipe/bedrock_db.php';
require 'vendor/mmoollllee/bedrock-deployer/recipe/bedrock_env.php';
require 'vendor/mmoollllee/bedrock-deployer/recipe/bedrock_auth.php';
Expand Down

0 comments on commit e4f3c5a

Please sign in to comment.