Skip to content

Commit

Permalink
AL-1612 - Added an initialization check to env:clone-content for the …
Browse files Browse the repository at this point in the history
…target environment in order to prevent workflow error (#1930)

* Changed env:clone-content to check both environments before attempting to clone

* Fixed the unit tests

* Added additional unit test for the cloning-to-an-uninitialized-env scenario

* Updated the PR number on the CHANGELOG additions

* Update the language on the uninitialized-clone advisories to indicate directionality (into/from)
  • Loading branch information
TeslaDethray authored Jan 22, 2019
1 parent b953f0d commit 5f7cd45
Show file tree
Hide file tree
Showing 8 changed files with 387 additions and 63 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ All notable changes to this project will be documented in this file. This projec
- Lock::serialize() 'locked' attribute has changed from string to boolean. (#1923)
- `Pantheon\Terminus\Friends\RowsOfFieldsTrait` has become `Pantheon\Terminus\Commands\StructuredDataTrait`. (#1923)
- `Backup::getUrl()` has been changed to `Backup::getArchiveURL()`. (#1923)
- Changed Environment::cloneDatabase() to accept an Environment object. (#1930)
- Changed Environment::cloneFiles() to accept an Environment object. (#1930)
- The target environment used in `env:clone-content` is now checked for initialization prior to cloning. (#1930)

### Deprecated
- `service-level:set` is now deprecated. Please use `plan:set`. (#1901)
Expand Down
111 changes: 85 additions & 26 deletions src/Commands/Env/CloneContentCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
use League\Container\ContainerAwareTrait;
use Pantheon\Terminus\Commands\TerminusCommand;
use Pantheon\Terminus\Exceptions\TerminusException;
use Pantheon\Terminus\Models\Environment;
use Pantheon\Terminus\Models\Workflow;
use Pantheon\Terminus\ProgressBars\WorkflowProgressBar;
use Pantheon\Terminus\Site\SiteAwareInterface;
use Pantheon\Terminus\Site\SiteAwareTrait;
Expand All @@ -19,6 +21,16 @@ class CloneContentCommand extends TerminusCommand implements ContainerAwareInter
use ContainerAwareTrait;
use SiteAwareTrait;

/**
* @var Environment
*/
private $source_env;
/**
* @var Environment
*/
private $target_env;


/**
* Clones database/files from one environment to another environment.
*
Expand All @@ -41,43 +53,90 @@ class CloneContentCommand extends TerminusCommand implements ContainerAwareInter
public function cloneContent($site_env, $target_env, array $options = ['db-only' => false, 'files-only' => false,])
{
if (!empty($options['db-only']) && !empty($options['files-only'])) {
throw new TerminusException("You cannot specify both --db-only and --files-only");
throw new TerminusException('You cannot specify both --db-only and --files-only');
}

list($site, $env) = $this->getUnfrozenSiteEnv($site_env);
$from_name = $env->getName();
$target = $site->getEnvironments()->get($target_env);
$to_name = $target->getName();
list($site, $this->source_env) = $this->getUnfrozenSiteEnv($site_env);
$this->target_env = $site->getEnvironments()->get($target_env);

$tr = ['from' => $from_name, 'to' => $to_name, 'site' => $site->getName(),];
if (!$env->isInitialized()) {
throw new TerminusException(
"{site}'s {from} environment cannot be cloned because it has not been initialized. Please run `env:deploy {site}.{from}` to initialize it.",
$tr
);
}
if (!$this->confirm('Are you sure you want to clone content from {from} to {to} on {site}?', $tr)) {
$this->checkForInitialization($this->source_env, 'from');
$this->checkForInitialization($this->target_env, 'into');
if (!$this->confirm(
'Are you sure you want to clone content from {from} to {to} on {site}?',
[
'from' => $this->source_env->getName(),
'site' => $site->getName(),
'to' => $this->target_env->getName(),
]
)) {
return;
}

if (empty($options['db-only'])) {
$workflow = $target->cloneFiles($from_name);
$this->log()->notice(
"Cloning files from {from_name} environment to {target_env} environment",
compact(['from_name', 'target_env'])
);
$this->getContainer()->get(WorkflowProgressBar::class, [$this->output, $workflow,])->cycle();
$this->log()->notice($workflow->getMessage());
$this->cloneFiles();
}

if (empty($options['files-only'])) {
$workflow = $target->cloneDatabase($from_name);
$this->log()->notice(
"Cloning database from {from_name} environment to {target_env} environment",
compact(['from_name', 'target_env'])
$this->cloneDatabase();
}
}

/**
* Checks to see whether the indicated environment is initialized and stops the process if it isn't
*
* @param Environment $env
* @param string $direction "into" or "from" are recommended.
* @throws TerminusException Thrown if the passed-in environment is not initialized
*/
private function checkForInitialization(Environment $env, $direction = '')
{
if (!$env->isInitialized()) {
throw new TerminusException(
"{site}'s {env} environment cannot be cloned ${direction} because it has not been initialized. Please run `env:deploy {site}.{env}` to initialize it.",
['env' => $env->getName(), 'site' => $env->getSite()->getName(),]
);
$this->getContainer()->get(WorkflowProgressBar::class, [$this->output, $workflow,])->cycle();
$this->log()->notice($workflow->getMessage());
}
}

/**
* Emits the cloning notice and clones runs the database cloning
*/
private function cloneDatabase()
{
$this->emitNotice('database');
$this->runClone($this->target_env->cloneDatabase($this->source_env));
}

/**
* Emits the cloning notice and clones runs the files cloning
*/
private function cloneFiles()
{
$this->emitNotice('files');
$this->runClone($this->target_env->cloneFiles($this->source_env));
}

/**
* Emits the cloning notice
*
* @param string $element
*/
private function emitNotice($element)
{
$this->log()->notice(
"Cloning ${element} from {source} environment to {target} environment",
['source' => $this->source_env->getName(), 'target' => $this->target_env->getName(),]
);
}

/**
* Runs the clone workflow with a progress bar
*
* @param Workflow $workflow
*/
private function runClone(Workflow $workflow)
{
$this->getContainer()->get(WorkflowProgressBar::class, [$this->output, $workflow,])->cycle();
$this->log()->notice($workflow->getMessage());
}
}
12 changes: 6 additions & 6 deletions src/Models/Environment.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,24 +143,24 @@ public function clearCache()
/**
* Clones database from this environment to another
*
* @param string $from_env Name of the environment to clone
* @param Environment $from_env An object representing the environment to clone
* @return Workflow
*/
public function cloneDatabase($from_env)
public function cloneDatabase(Environment $from_env)
{
$params = ['from_environment' => $from_env,];
$params = ['from_environment' => $from_env->getName(),];
return $this->getWorkflows()->create('clone_database', compact('params'));
}

/**
* Clones files from this environment to another
*
* @param string $from_env Name of the environment to clone
* @param Environment $from_env An object representing the environment to clone
* @return Workflow
*/
public function cloneFiles($from_env)
public function cloneFiles(Environment $from_env)
{
$params = ['from_environment' => $from_env,];
$params = ['from_environment' => $from_env->getName(),];
return $this->getWorkflows()->create('clone_files', compact('params'));
}

Expand Down
14 changes: 11 additions & 3 deletions tests/features/env-clone.feature
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,18 @@ Feature: Cloning site content
Cloned database from "test" to "dev"
"""

@vcr env-clone-uninitialized.yml
Scenario: Attempting to clone an uninitialized environment
@vcr env-clone-from-uninitialized.yml
Scenario: Attempting to clone from an uninitialized environment
When I run "terminus env:clone-content [[test_site_name]].test dev --db-only --yes"
Then I should get:
"""
[[test_site_name]]'s test environment cannot be cloned because it has not been initialized. Please run `env:deploy [[test_site_name]].test` to initialize it.
[[test_site_name]]'s test environment cannot be cloned from because it has not been initialized. Please run `env:deploy [[test_site_name]].test` to initialize it.
"""

@vcr env-clone-to-uninitialized.yml
Scenario: Attempting to clone to an uninitialized environment
When I run "terminus env:clone-content [[test_site_name]].test live --db-only --yes"
Then I should get:
"""
[[test_site_name]]'s live environment cannot be cloned into because it has not been initialized. Please run `env:deploy [[test_site_name]].live` to initialize it.
"""
File renamed without changes.
Loading

0 comments on commit 5f7cd45

Please sign in to comment.